您的位置:首页 > 其它

蓝桥杯 历届试题 矩阵翻硬币

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)还很远很远!

有数论基础的应该都会知道约数个数与分解质因数有关:



根据奇偶性,必须每一项都是奇数。

也就是每个

都是偶数,

即原数是一个完全平方数!

那么答案就很明显了:



总之一道在图上搞了半天的题变成了一个式子解决。

不觉得很有意思吗?

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  蓝桥杯