蓝桥杯 历届试题 矩阵翻硬币
2015-11-17 21:54
204 查看
问题描述
小明先把硬币摆成了一个 n 行 m 列的矩阵。
随后,小明对每一个硬币分别进行一次 Q 操作。
对第x行第y列的硬币进行 Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进行翻转。
其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。
当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。
小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。
聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。
输入格式
输入数据包含一行,两个正整数 n m,含义见题目描述。
输出格式
输出一个正整数,表示最开始有多少枚硬币是反面朝上的。
样例输入
2 3
样例输出
1
数据规模和约定
对于10%的数据,n、m <= 10^3;
对于20%的数据,n、m <= 10^7;
对于40%的数据,n、m <= 10^15;
对于10%的数据,n、m <= 10^1000(10的1000次方)。
感觉这题很有意思。
其实看看数据范围就知道应该是O(1)算法 ←_←
下面开始推:
有两个变量我们一般分开来看。
如果一个硬币在第二行,那么它可能被第一行和第二行的硬币翻转。
更一般地,如果一个硬币在第x行,那么它可能被第p行的硬币翻转的,其中p是x的约数。
列也是同理。
正反面问题实际上是个奇偶性问题,更进一步的是一个计数问题!
这里把约数个数用
表示,
再奇偶性判定用位运算描述,
那么答案等于:
开始有意思了是吗?
但是这样离O(1)还很远很远!
有数论基础的应该都会知道约数个数与分解质因数有关:
根据奇偶性,必须每一项都是奇数。
也就是每个
都是偶数,
即原数是一个完全平方数!
那么答案就很明显了:
总之一道在图上搞了半天的题变成了一个式子解决。
不觉得很有意思吗?
小明先把硬币摆成了一个 n 行 m 列的矩阵。
随后,小明对每一个硬币分别进行一次 Q 操作。
对第x行第y列的硬币进行 Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进行翻转。
其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。
当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。
小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。
聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。
输入格式
输入数据包含一行,两个正整数 n m,含义见题目描述。
输出格式
输出一个正整数,表示最开始有多少枚硬币是反面朝上的。
样例输入
2 3
样例输出
1
数据规模和约定
对于10%的数据,n、m <= 10^3;
对于20%的数据,n、m <= 10^7;
对于40%的数据,n、m <= 10^15;
对于10%的数据,n、m <= 10^1000(10的1000次方)。
感觉这题很有意思。
其实看看数据范围就知道应该是O(1)算法 ←_←
下面开始推:
有两个变量我们一般分开来看。
如果一个硬币在第二行,那么它可能被第一行和第二行的硬币翻转。
更一般地,如果一个硬币在第x行,那么它可能被第p行的硬币翻转的,其中p是x的约数。
列也是同理。
正反面问题实际上是个奇偶性问题,更进一步的是一个计数问题!
这里把约数个数用
表示,
再奇偶性判定用位运算描述,
那么答案等于:
开始有意思了是吗?
但是这样离O(1)还很远很远!
有数论基础的应该都会知道约数个数与分解质因数有关:
根据奇偶性,必须每一项都是奇数。
也就是每个
都是偶数,
即原数是一个完全平方数!
那么答案就很明显了:
总之一道在图上搞了半天的题变成了一个式子解决。
不觉得很有意思吗?
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; struct bigData { int s[1100]; int len; }; void input(bigData &a) { char s[1100]; scanf("%s",s); long long x=0; int i=0,j=0; int l=strlen(s); a.len=0; memset(a.s,0,sizeof(a.s)); for (j=1;j<=l/4;j++) { for (x=0,i=l-4*j;i<l+4-4*j;i++) x=x*10+s[i]-'0'; a.s[j]=x; } for (x=0,i=0;i<l%4;i++) x=x*10+s[i]-'0'; if (x) a.s[j++]=x; a.len=j-1; } int bigCmp(bigData a,bigData b) { if (a.len>b.len) return 1; if (a.len<b.len) return -1; int i=a.len,j=b.len; for (;i>0&&j>0&&a.s[i]==b.s[j];i--,j--); if (i==0&&j==0) return 0; if (a.s[i]>b.s[j]) return 1; if (a.s[i]<b.s[j]) return -1; return -2; } bigData bigMul(bigData a,bigData b) { int la=a.len; int lb=b.len; int l=la+lb-1; bigData c; int x=0; c.len=l; memset(c.s,0,sizeof(c.s)); for (int i=1;i<=la;i++) { for (int j=1;j<=lb;j++) { c.s[i+j-1]+=x+a.s[i]*b.s[j]; c.s[i+j]+=c.s[i+j-1]/10000; c.s[i+j-1]%=10000; } } if (c.s[l+1]) c.len++; while (c.len>1&&c.s[c.len]==0) c.len--; return c; } void output(bigData a) { int l=a.len,i=0; printf("%d",a.s[l]); for (i=l-1;i>0;i--) { if (a.s[i]<10) printf("000"); else if (a.s[i]<100) printf("00"); else if (a.s[i]<1000) printf("0"); printf("%d",a.s[i]); } puts(""); } bigData bigSqrt(bigData a) { int lc=(a.len+1)/2,i; bigData c; c.len=lc; memset(c.s,0,sizeof(c.s)); for (i=lc;i>0;i--) { int f=0; do { c.s[i]+=1000; f=bigCmp(a,bigMul(c,c)); if (f==0) break; } while (f==1); if (f==0) break; c.s[i]-=1000; do { c.s[i]+=100; f=bigCmp(a,bigMul(c,c)); if (f==0) break; } while (f==1); if (f==0) break; c.s[i]-=100; do { c.s[i]+=10; f=bigCmp(a,bigMul(c,c)); if (f==0) break; } while (f==1); if (f==0) break; c.s[i]-=10; do { c.s[i]++; f=bigCmp(a,bigMul(c,c)); if (f==0) break; } while (f==1); if (f==0) break; c.s[i]--; } return c; } int main() { bigData a,b,c; input(a); input(b); c=bigMul(bigSqrt(a),bigSqrt(b)); output(c); // printf("%d\n",bigCmp(a,b)); return 0; }