这是第一篇,写的目的就是督促自己每天多学一点为主,要是有朋友看见了请不要吐槽我的排版。同时由于我水平有限,我的程序也有时会拿不到满分(很尴尬第一篇就只拿到90%),发现问题在哪欢迎告诉我。
这些算法在用做题之前多数是不太懂的,做每个算法题都参考了各路算法大牛的博客才学会。所以我写的内容或多或少会带有其他博主的影子,但是重点是我力图把我学习中理解上的一些难点用我自己的体会通俗的描述出来,以达到集百家之长的目的。
步入正题,来看题目。
问题描述
小明先把硬币摆成了一个 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次方)。
涉及知识点:大数相乘,大数开平方,公约数的性质,奇偶数的性质
#include<stdio.h>
#include<string.h>
#define MAX 1010
int temp[MAX];
//乘法函数,结果存在save中
int multip(int save[],int fir[],int sed[],int len_fir,int len_sed)
{
int i,j,k,len,temp;
for(i=len_fir-1;i>=0;i--)
{
for(j=len_sed-1;j>=0;j--)
{
save[i+j+1] += fir[i]*sed[j];
}
}
for(i=len_fir+len_sed-1 ; i>0 ; i--)
{
save[i-1] += save[i]/10;
save[i] = save[i]%10;
}
//判断相乘后有几位
i=0;
while(save[i]==0 && i<len_fir+len_sed)
{
i++;
}
len = len_fir+len_sed-i ;
j=i;
for(i=0;i<len;i++)
{
save[i]=save[i+j];
}
save[len]='\0';
return len;
}
//比较函数,如果sqr的平方大于pro返回0,否则返回1
int compare(int pro[],int sqr[],int len,int len_s)
{
int i;
int flag=0;//当判断到sqr的平方大于pro时flag标记为1
int get_len;
memset(temp,0,sizeof(temp));
get_len = multip(temp,sqr,sqr,len_s,len_s);
//首先根据长度判断大小
if(get_len < len)
{
return 1;
}else if(get_len > len)
{
return 0;
}
for(i=0;i<len;i++)
{
if(temp[i]<pro[i])
{
flag = 0;
break;
}else if(temp[i]>pro[i])
{
flag = 1;
break;
}
}
if(flag == 1)
{
// printf("len_s=%d sqr=%d temp=%d\n",len_s,sqr[0],temp[0]);
return 0;
}else{
return 1;
}
}
int getsqrt(int len,int pro[],int sqr[])
{
int i,int_len;
//开平方后的位数
if(len%2 == 0)
{
int_len = len/2;
}else{
int_len = (len+1)/2;
}
for(i=0;i<int_len;i++)
{
while(compare(pro,sqr,len,int_len))
{
sqr[i]++;
}
sqr[i]--;
}
return int_len;
}
int main()
{
char n[MAX],m[MAX];
int int_n[MAX],int_m[MAX];
int sqrt_n[MAX],sqrt_m[MAX];
int lenn,lenm,len,i;
scanf("%s %s",n,m);
lenn = strlen(n); //行数n的位数
lenm = strlen(m); //列数m的位数
//将字符型数字转化为int,便于后续计算
for(i=0;i<lenn;i++)
{
int_n[i] = n[i]-'0';
}
for(i=0;i<lenm;i++)
{
int_m[i] = m[i]-'0';
}
memset(sqrt_n,0,sizeof(int)*MAX);//初始化为0
memset(sqrt_m,0,sizeof(int)*MAX);
lenn = getsqrt(lenn,int_n,sqrt_n);//计算行值开平方后所得的数,存储在sqrt_n中
lenm = getsqrt(lenm,int_m,sqrt_m);//计算列值开平方后所得的数,存储在sqrt_m中
memset(temp,0,sizeof(temp));
len = multip(temp,sqrt_n,sqrt_m,lenn,lenm);
for(i=0;i<len;i++)
{
printf("%d",temp[i]);
}
return 0;
}