您的位置:首页 > 编程语言 > Go语言

algorithm 题集五 (16.07.20)

2016-07-20 21:15 429 查看

acdream 1213 Matrix Multiplication

http://acdream.info/problem?pid=1213

大意:定义矩阵A,a_{ij}=1表示i结点是边j的一个端点。其他部分是0,。求解A^{T}A中数值的和。

分析:A^{T}A的结果

举例子找规律:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const LL N=1e4+10;
const int n=4;
struct matrix{
LL m

;
};
matrix A={
1,1,0,0,
2,0,2,3,
0,1,1,0,
0,0,0,1
};
matrix multi(matrix a,matrix b){
matrix ans;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++){
ans.m[i][j]+=a.m[i][k]*b.m[k][j];
}
}
}
return ans;
}
void show(matrix F){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%3d",F.m[i][j]);
}
puts("");
}
}
int main()
{
matrix B;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
B.m[j][i]=A.m[i][j];
}
}
show(A);
cout<<"--------------\n";
show(B);
matrix C=multi(B,A);
cout<<"--------------\n";
show(C);
return 0;
}
/*
A:
1  1  0  0
1  0  1  1
0  1  1  0
0  0  0  1
--------------
A^{T}
1  1  0  0
1  0  1  0
0  1  1  0
0  1  0  1
--------------
A^{T}A:
2  1  1  1
1  2  1  0
1  1  2  1
1  0  1  2
*/


可以发现这是一个对称矩阵,且元素的和就是对角线元素的平方和。对交线元素的值就是结点在各个边出现的次数,即“度”。注意,这样的规律仅仅出现在01矩阵中。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;
const LL N=1e4+10;
LL g
,x,y;

int main()
{
LL n,m;
while(cin>>n>>m){
memset(g,0,sizeof(g));
for(LL i=0;i<m;i++){
scanf("%lld%lld",&x,&y);
g[x]++;   g[y]++;
}
LL ans=0;
for(LL i=1;i<=n;i++){
ans=ans+g[i]*g[i];
}
printf("%lld\n",ans);
}
return 0;
}


codeforces 675C. Money Transfers

http://codeforces.com/problemset/problem/675/C

大意:一个人在n个银行存钱,n各银行的排列呈现一个环形。1和n是相邻的。人在各个银行中的存款是有正有负的。转移操作:把银行里的钱转到相邻的银行,问经过多少的转移操作可以把所有的银行的钱变成0?

分析:先看几个简单的例子。

1 0 -1 anwer: 1

1 2 3 -6 anwer: 3

看起来,最佳的答案和转移操作的方向有关系。对于3的情况是3=4-1 可以发现,理想情况下,答案就是n-1. 非理想情况下,就是各个理想情况的累计。设和是0的分段数是k.

anwer=∑i=1k(li−1)=n−k

现在的重点是计算这个k

观察:

数字:

1
0   0
-1

对应和:
1
0   1
0


设数字i出现了k次,那么它一定包含了k-1个0段,一个-i段。即k个0段。

所以我们计算最大的k即可。

#include <iostream>
#include <cstdio>
#include <map>
using namespace std;

const int N=1e5+10;

int main()
{
int n;
while(cin>>n){
int ans=0,a;
long long temp=0;
map<long long,int> mp;
for(int i=0;i<n;i++) {
scanf("%d",&a);
temp+=a;
mp[temp]++;
ans=ans>mp[temp]?ans:mp[temp];
}
printf("%d\n",n-ans);
}
return 0;
}


codeforces 678 C. Joty and Chocolate

http://codeforces.com/problemset/problem/678/C

大意:有n块瓷砖,标记为1——n,如果能被a整除,那么染成红色,得到p块巧克力;如果能被b整除,那么染成蓝色,得到q块巧克力。

问能得到的最多的巧克力是多少?

分析:贪心策略。分析p和q的大小关系,然后尽可能给值大的染色。(注意去重问题)

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b){
return b==0?a:gcd(b,a%b);
}

int main(){
 LL n,a,b,p,q;
while(~scanf("%I64d%I64d%I64d%I64d%I64d",&n,&a,&b,&p,&q)){
LL lcm=a/gcd(a,b)*b;
LL over=n/lcm;
LL na=n/a, nb=n/b;
LL ans=0;
if(p<q) ans=nb*q+(na-over)*p;
else ans=na*p+(nb-over)*q;
printf("%I64d\n",ans);
}
return 0;
}


codeforces 675B. Restoring Painting

http://codeforces.com/problemset/problem/675/B

大意:在下图中直接填数,所填数字是1<=x<=n,

使得,四个相邻的方格的和等于左上角的数字的和。问方案数。



设方格是这样的:

x1bx3aydx2cx4

然后我们有:

a+b+y+x1=sa+c+y+x2=sb+d+y+x3=sd+c+y+x4=s

转换:

a+b+x1=sa+c+x2=sb+d+x3=sd+c+x4=s

恩,直接把一个二重循环变成一重循环。

codeforces 678 D. Iterated Linear Function

http://www.codeforces.com/contest/678/problem/D

题目:Consider a linear function f(x) = Ax + B. Let’s define g(0)(x) = x and g(n)(x) = f(g(n - 1)(x)) for n > 0. For the given integer values A, B, n and x find the value of g(n)(x) modulo 109 + 7.

分析:因为存在着明显的线性关系,加上数字特别大,所以考虑用到矩阵快速幂。

递推式:

⎛⎝⎜gn(x)gn−1(x)1⎞⎠⎟=⎛⎝⎜A10000B01⎞⎠⎟×⎛⎝⎜gn−1(x)gn−2(x)1⎞⎠⎟

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
struct matrix{
LL m[3][3];
};
matrix mt={
0,0,0,
1,0,0,
0,0,1
};
matrix I={
1,0,0,
0,1,0,
0,0,1
};
matrix multi(matrix a,matrix b){
matrix  ans;
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
ans.m[i][j]=0;
for(int k=0;k<3;k++){
ans.m[i][j]+=a.m[i][k]*b.m[k][j];
}
ans.m[i][j]%=mod;
}
}
return ans;
}
matrix power(matrix pr, LL n){
matrix ans=I,temp=pr;
while(n){
if(n&1) ans=multi(ans,temp);
temp=multi(temp,temp);
n>>=1;
}
return ans;
}
int main()
{
LL A,B,n,x;
while(cin>>A>>B>>n>>x){
mt.m[0][0]=A;
mt.m[0][2]=B;
matrix tr=mt;
tr=power(tr,n-1);
LL g0=x,g1=(A*x%mod+B)%mod;
LL gn=(g1*tr.m[0][0]%mod+tr.m[0][2])%mod;
if(n>1) cout<<gn<<endl;
else cout<<g1<<endl;
}
return 0;
}


高精度 (C++版 )

acdream 1210 Chinese Girls’ Amusement

http://acdream.info/problem?pid=1210

大意:给出一个大数, N (3 ≤ N ≤ 10 2000),求解尽可能大的数字k (k<=N/2),使得i=0,(i+k)%N,遍历完0~N-1。【题目中的说的意思是 If for example N = 7 and K = 3, the girls receive the ball in the following order: 1, 4, 7, 3, 6, 2, 5, 1.】

分析:首先一定有gcd(N,k)=1。于是可以用java暴力找规律。

通过数学分析规律,我们知道有一些特别的式子,(2k+1,k)=1, (k,k-1)=1. 那么可以知道

当N是奇数时,(N-1)/2即为所求;

当N是一个偶数,那么N’=N>>1,

当N’是一个偶数,N’-1就是一个奇数,则N’-1和2、N’均互质,所以N’-1就是答案;

当N’是一个奇数,N’-1就是一个偶数,N’-1和2不是互质的,N’-2则和2互质,且与N’互

质 ,即为答案。(不用考虑2)

用java写一直dangerous code,改用C++

大数模板来自于kuangbin:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int MX = 2500;
const int MAXN = 9999;
const int DLEN = 4;

class Big {
public:
int a[MX], len;
Big(const int b = 0) {
int c, d = b;
len = 0;
memset(a, 0, sizeof(a));
while(d > MAXN) {
c = d - (d / (MAXN + 1)) * (MAXN + 1);
d = d / (MAXN + 1);
a[len++] = c;
}
a[len++] = d;
}
Big(const char *s) {
int t, k, index, L, i;
memset(a, 0, sizeof(a));
L = strlen(s);
len = L / DLEN;
if(L % DLEN) len++;
index = 0;
for(i = L - 1; i >= 0; i -= DLEN) {
t = 0;
k = i - DLEN + 1;
if(k < 0) k = 0;
for(int j = k; j <= i; j++) {
t = t * 10 + s[j] - '0';
}
a[index++] = t;
}
}
Big operator/(const int &b)const {  //大数除以整数
Big ret;
int i, down = 0;
for(i = len - 1; i >= 0; i--) {
ret.a[i] = (a[i] + down * (MAXN + 1)) / b;
down = a[i] + down * (MAXN + 1) - ret.a[i] * b;
}
ret.len = len;
while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
return ret;
}
bool operator>(const Big &T)const {
int ln;
if(len > T.len) return true;
else if(len == T.len) {
ln = len - 1;
while(a[ln] == T.a[ln] && ln >= 0) ln--;
if(ln >= 0 && a[ln] > T.a[ln]) return true;
else return false;
} else return false;
}
Big operator+(const Big &T)const {
Big t(*this);
int i, big;
big = T.len > len ? T.len : len;
for(i = 0; i < big; i++) {
t.a[i] += T.a[i];
if(t.a[i] > MAXN) {
t.a[i + 1]++;
t.a[i] -= MAXN + 1;
}
}
if(t.a[big] != 0) t.len = big + 1;
else t.len = big;
return t;
}
Big operator-(const Big &T)const {
int i, j, big;
bool flag;
Big t1, t2;
if(*this > T) {
t1 = *this;
t2 = T;
flag = 0;
} else {
t1 = T;
t2 = *this;
flag = 1;
}
big = t1.len;
for(i = 0; i < big; i++) {
if(t1.a[i] < t2.a[i]) {
j = i + 1;
while(t1.a[j] == 0) j++;
t1.a[j--]--;
while(j > i) t1.a[j--] += MAXN;
t1.a[i] += MAXN + 1 - t2.a[i];
} else t1.a[i] -= t2.a[i];
}
t1.len = big;
while(t1.a[t1.len - 1] == 0 && t1.len > 1) {
t1.len--;
big--;
}
if(flag) t1.a[big - 1] = 0 - t1.a[big - 1];
return t1;
}
int operator%(const int &b)const {   //大数对余数取模
int i, d = 0;
for(i = len - 1; i >= 0; i--) {
d = ((d * (MAXN + 1)) % b + a[i]) % b;
}
return d;
}
Big operator*(const Big &T) const {
Big ret;
int i, j, up, temp, temp1;
for(i = 0; i < len; i++) {
up = 0;
for(j = 0; j < T.len; j++) {
temp = a[i] * T.a[j] + ret.a[i + j] + up;
if(temp > MAXN) {
temp1 = temp - temp / (MAXN + 1) * (MAXN + 1);
up = temp / (MAXN + 1);
ret.a[i + j] = temp1;
} else {
up = 0;
ret.a[i + j] = temp;
}
}
if(up != 0) {
ret.a[i + j] = up;
}
}
ret.len = i + j;
while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
return ret;
}
void print() {
printf("%d", a[len - 1]);
for(int i = len - 2; i >= 0; i--) printf("%04d", a[i]);
puts("");
}
};

int main() {
char word[MX];
while(~scanf("%s", word)) {
Big n(word);
Big one("1");
if(n.a[0]&1) {
n=n-one;
n=n/2;
n.print();
}
else {
n=n/2;
n=n-one;
if(n.a[0]&1) n.print();
else {
n=n-one;
n.print();
}
}
}
return 0;
}


acdream 1667 调皮的数一(递推+高精度)

http://acdream.info/problem?pid=1667

题意:

数一很喜欢跑步~喜欢追逐风的脚步~

但是数一永远改不了贪玩调皮的个性,他在跑步的时候经常跑到别的跑道上。假设数一在跑一条直线跑道,从左往右是1号跑道,2号跑道,3号跑道…… 如此类推,并且为了让数一同学更自由,总共有无限条跑道!数一需要跑n步才能到达终点,但是正如上面所说的,他每跑一步要么仍然在原跑道,要么蹿到相邻的 跑道,当然数一是不会跑到1号跑道之外的,因为这是违背数一原则的!数一,顾名思义,肯定是从1号跑道开始跑步,同样的,最后必须回到1号跑道到达终点。 那么请问数一有多少种方案来跑完这n步呢?(两种方案视为不同当且仅当两种方案的某一步所在的跑道不同)

分析:开始递归打表找规律,没有发现明显的规律。

#include <iostream>
using namespace std;
int sum,n;
void get(int s,int now,int step){
if(step==n){
if(now==s)  sum++;
return ;
}
get(s,now+1,step+1);
get(s,now,step+1);
if(now-1>=1) get(s,now-1,step+1);
}
int main()
{
n=1;
while(n<100){
sum=0;
int s=1;
get(s,s,0);
cout<<n<<": "<<sum<<endl;
n++;
}
return 0;
}
/*
1: 1
2: 2
3: 4
4: 9
5: 21
6: 51
7: 127
8: 323
9: 835
10: 2188
11: 5798
12: 15511
13: 41835
14: 113634
15: 310572
16: 853467
17: 2356779
18: 6536382
19: 18199284
20: 50852019
*/


然后,直接用java递推吧。设i是步数,j是跑道,那么

dp[i][j]=dp[i−1][j−1]+dp[i−1][j]+dp[i−1][j+1]

import java.util.*;
import java.math.BigInteger;
import java.io.*;
public class Main {
public static void main(String[] args) {
BigInteger zero=BigInteger.ZERO;
BigInteger one= BigInteger.ONE;
BigInteger two=BigInteger.valueOf(2);
BigInteger [][]dp=new BigInteger[1005][1005];
for(int i=0;i<1005;i++){
for(int j=0;j<1005;j++) dp[i][j]=zero;
}

dp[1][1]=one;  dp[1][2]=one;
for(int i=2;i<1005;i++){
for(int j=1;j<1005;j++) {
if(j>1)dp[i][j] = dp[i - 1][j - 1]; // left
else dp[i][j]=zero;
dp[i][j] = dp[i][j].add(dp[i - 1][j]); // self
if(j+1<1005) dp[i][j] = dp[i][j].add(dp[i - 1][j + 1]);  //right
}
}
Scanner cin = new Scanner(new BufferedInputStream(System.in));
int n;
while(cin.hasNext()) {
n=cin.nextInt();
System.out.println(dp
[1]);
}
}
}

/*
1
2 2
4 5 3
9 12 9 4
21 30 25 14 5
51 76 69 44 20 6
127 196 189 133 70 27 7
323 512 518 392 230 104 35 8
835 1353 1422 1140 726 369 147 44 9
2188 3610 3915 3288 2235 1242 560 200 54 10
5798 9713 10813 9438 6765 4037 2002 814 264 65 11
15511 26324 29964 27016 20240 12804 6853 3080 1143 340 77 12
41835 71799 83304 77220 60060 39897 22737 11076 4563 1560 429 90 13
113634 196938 232323 220584 177177 122694 73710 38376 17199 6552 2079 532 104 14
310572 542895 649845 630084 520455 373581 234780 129285 62127 25830 9163 2715 650 119 15
*/


提交上去居然是dangerous code。无语

java代码还是有用的,看看了1000对应的答案,它的长度不超过500. 这为C++高精度写这道题做出了贡献!

61132765976771855043569047663477026123545749714656085011546589236155495722766969901079431830293889711348439744195266975094911612991797833366353410859516867069848930242882249040334833576823874286962329988371694936795430251830268276815069432020192175034116717998885556302695758962184096918871220935603669769530006544625695194401924619329879493165824888357109725170564975207916931034666534175155289953905326098910534128693214689917140093377138459245912955193770266157466468457

C++高精度版本:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

const int N=500,M=1009;
const int MX = 150;
const int MAXN = 9999;
const int DLEN = 4;

class Big {
public:
int a[MX], len;
Big(const int b = 0) {
int c, d = b;
len = 0;
memset(a, 0, sizeof(a));
while(d > MAXN) {
c = d - (d / (MAXN + 1)) * (MAXN + 1);
d = d / (MAXN + 1);
a[len++] = c;
}
a[len++] = d;
}
Big(const char *s) {
int t, k, index, L, i;
memset(a, 0, sizeof(a));
L = strlen(s);
len = L / DLEN;
if(L % DLEN) len++;
index = 0;
for(i = L - 1; i >= 0; i -= DLEN) {
t = 0;
k = i - DLEN + 1;
if(k < 0) k = 0;
for(int j = k; j <= i; j++) {
t = t * 10 + s[j] - '0';
}
a[index++] = t;
}
}
Big operator/(const int &b)const {  //大数除以整数
Big ret;
int i, down = 0;
for(i = len - 1; i >= 0; i--) {
ret.a[i] = (a[i] + down * (MAXN + 1)) / b;
down = a[i] + down * (MAXN + 1) - ret.a[i] * b;
}
ret.len = len;
while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
return ret;
}
bool operator>(const Big &T)const {
int ln;
if(len > T.len) return true;
else if(len == T.len) {
ln = len - 1;
while(a[ln] == T.a[ln] && ln >= 0) ln--;
if(ln >= 0 && a[ln] > T.a[ln]) return true;
else return false;
} else return false;
}
Big operator+(const Big &T)const {
Big t(*this);
int i, big;
big = T.len > len ? T.len : len;
for(i = 0; i < big; i++) {
t.a[i] += T.a[i];
if(t.a[i] > MAXN) {
t.a[i + 1]++;
t.a[i] -= MAXN + 1;
}
}
if(t.a[big] != 0) t.len = big + 1;
else t.len = big;
return t;
}
Big operator-(const Big &T)const {
int i, j, big;
bool flag;
Big t1, t2;
if(*this > T) {
t1 = *this;
t2 = T;
flag = 0;
} else {
t1 = T;
t2 = *this;
flag = 1;
}
big = t1.len;
for(i = 0; i < big; i++) {
if(t1.a[i] < t2.a[i]) {
j = i + 1;
while(t1.a[j] == 0) j++;
t1.a[j--]--;
while(j > i) t1.a[j--] += MAXN;
t1.a[i] += MAXN + 1 - t2.a[i];
} else t1.a[i] -= t2.a[i];
}
t1.len = big;
while(t1.a[t1.len - 1] == 0 && t1.len > 1) {
t1.len--;
big--;
}
if(flag) t1.a[big - 1] = 0 - t1.a[big - 1];
return t1;
}
int operator%(const int &b)const {   //大数对余数取模
int i, d = 0;
for(i = len - 1; i >= 0; i--) {
d = ((d * (MAXN + 1)) % b + a[i]) % b;
}
return d;
}
Big operator*(const Big &T) const {
Big ret;
int i, j, up, temp, temp1;
for(i = 0; i < len; i++) {
up = 0;
for(j = 0; j < T.len; j++) {
temp = a[i] * T.a[j] + ret.a[i + j] + up;
if(temp > MAXN) {
temp1 = temp - temp / (MAXN + 1) * (MAXN + 1);
up = temp / (MAXN + 1);
ret.a[i + j] = temp1;
} else {
up = 0;
ret.a[i + j] = temp;
}
}
if(up != 0) {
ret.a[i + j] = up;
}
}
ret.len = i + j;
while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
return ret;
}
void print() {
printf("%d", a[len - 1]);
for(int i = len - 2; i >= 0; i--) printf("%04d", a[i]);
puts("");
}
};

int main()
{
Big one("1");
Big zero("0");
Big dp[3][M];  //内存不够——使用滚动数组
dp[1][1]=one;  dp[1][2]=one;
dp[0][1]=dp[1][1];
for(int i=2;i<M;i++){
for(int j=1;j<M;j++) {
if(j>1)dp[2][j] = dp[1][j - 1]; // left
else dp[2][j]=zero;
dp[2][j] = dp[2][j]+dp[1][j]; // self
if(j+1<1005) dp[2][j] = dp[2][j]+dp[1][j + 1];  //right
}
for(int j=1;j<=M;j++) dp[1][j]=dp[2][j];
//if(i<100)dp[1][1].print();
dp[0][i]=dp[1][1];  //answer
}

int n;
while(cin>>n){
dp[0]
.print();
}
return 0;
}


51nod 1005 大数加法 (发现C++高精度的bug)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1005

Input

第1行:大数A

第2行:大数B

(A,B的长度 <= 10000 需注意:A B有可能为负数)

Output

输出A + B

Input示例

68932147586

468711654886

Output示例

537643802472

分析:

这题用之前的C++模板做,出现了bug:

-9999999999

10000000000

答案竟是19999999999.

好吧,暂时没查出来问题在哪里,我猥琐的用java写了

import java.util.*;
import java.math.BigInteger;
public class Main {
public static void main(String[] args) {
Scanner cin=new Scanner (System.in);
while(cin.hasNext()){
BigInteger a=cin.nextBigInteger();
BigInteger b=cin.nextBigInteger();
System.out.println(a.add(b));
}
}
}


51nod 1605 棋盘问题

http://www.51nod.com/onlineJudge/problemSolution.html#!problemId=1605

上帝创造了一个n*m棋盘,每一个格子都只有可能是黑色或者白色的。

亚当和夏娃在玩一个游戏,每次寻找边长为x的正方形,其中每个格子必须为黑色,然后将这些格子染白。

如果谁不能操作了,那么那个人就输了。

亚当喜欢质数。

夏娃喜欢1,但讨厌2。

因此他们规定,x只有可能是非2质数或者是1。

现在他们想知道,如果他们都用最优策略进行游戏,谁会赢。

上帝规定亚当先手。

分析:自己是单纯的找出方块数及其规模。然后将各个规模分解成非2质数块和1块,统计块的数目,奇数就是亚当赢,否则就是夏娃赢。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int gra[105][105];
int sta[10010],top;
struct node{
int x,y;
node(const node &other){ x=other.x;  y=other.y; }
node(int _x,int _y){
x=_x;   y=_y;
}
};
bool vis[105];
void get_pri(){
for(int i=2;i<=100;i++){
for(int j=2;j*j<=i;j++){
if(i%j==0) vis[i]=0;
}
}
vis[2]=0;
vis[1]=1;
}

int main()
{
//freopen("cin.txt","r",stdin);
int t,n,m;
scanf("%d",&t);
get_pri();
while(t--){
scanf("%d%d",&n,&m);
memset(gra,0,sizeof(gra));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) scanf("%d",&gra[i][j]);
}
top=0;
int cnt=0;

for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(gra[i][j]==1){
node t0(i,j);
cnt=0;
while(gra[t0.x][t0.y]==1){
node t1(t0),t2(t0);
bool ok=1;
while(t1.y>=j) {
if(gra[t1.x][t1.y]==0) { ok=0;  break; }
t1.y--;
}
while(t2.x>=i){
if(gra[t2.x][t2.y]==0) { ok=0;  break; }
t2.x--;
}
if(ok) {
t0.x++;
t0.y++;
cnt++;
}
else break;
}
sta[top++]=cnt;
for(int x=i;x<t0.x;x++){
for(int y=j;y<t0.y;y++){
gra[x][y]=0;
}
}
}
}
}
int ans=top;
for(int i=0;i<top;i++){
if(vis[sta[i]]==0){
ans--;
int area=sta[i]*sta[i];
for(int j=sta[i]-1;j>=1;j--){
if(vis[j]) {
int ss=j*j;
ans+=area/ss;
area-=area/ss*ss;
}
}
}
}   //puts("");
if(ans&1) puts("yadang");
else puts("xiawa");
}
return 0;
}


看了解题报告,瞬间感觉自己太年轻了。

题解:

注意到边长只有可能是奇数。

因此每次操作将黑色变成白色的棋子数一定是奇数。

那么只要知道一开始时黑色棋子数量的奇偶,就能判断谁能赢了。

具体的,若是奇数,亚当胜,若是偶数,夏娃胜。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: