历届试题 矩阵翻硬币

问题描述
  小明先把硬币摆成了一个 n 行 m 列的矩阵。

随后,小明对每一个硬币分别进行一次 Q 操作。

对第x行第y列的硬币进行 Q 操作的定义:将所有第 ix 行,第 jy 列的硬币进行翻转。

其中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次方)。

这道题主要是找规律,然后需要高精度乘法的应用来开方.

//矩阵翻硬币
//主要用到高精度开方
//对于一个数 若他位数是偶数则他的开放数为len/2,若是奇数则为(len+2)/2 
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int num1[1005];  //保存n,m的值 
int num2[1005];
// 对高精度大数的比较大小 
int Compare(int A[],int B[])
{
	if(A[0]>B[0]) return 1;
	else if(A[0]<B[0]) return -1;
	else
	{
	 for(int i = A[0];i>=1;i--)
	 {
	  if(A[i]>B[i]) return 1;
	  else if(A[i]<B[i]) return -1;	
	 }	
	}
	return 0;
}
//高精度乘法操作 
void CF(int G[],int A[],int B[])
{

	int T[2020];
	memset(T,0,sizeof(T));
	T[0]=A[0]+B[0];
	for(int i=1;i<=A[0];i++)
	{
		for(int j = 1;j<=B[0];j++)
		{
			T[i+j-1]+=(A[i]*B[j]);
			T[i+j]+=(T[i+j-1]/10);
			T[i+j-1]%=10;
		}
	}
	while(T[T[0]]==0&&T[0]>0) T[0]--;
	for(int i =0;i<=T[0];i++)
	G[i]=T[i];
	return ;
}

void Sqrt(int A[]) //开方函数
{
  int len = (A[0]+1)/2;       //这是必定正确的
  int T[2020];
  memset(T,0,sizeof(T));
  T[0]=len;
  int tmp[2020];
  int flag=0;
  for(int i = len;i>0;i--)
  {
  	for(int j = 0;j<=9;j++)
  	{
  		T[i]=j;
  		CF(tmp,T,T);
  		if(Compare(tmp,A)==1) //如果比较的大于A 
  		{
  			T[i]=j-1;     //退回一个 
  			break;
		}
		else if(Compare(tmp,A)==0)
		{
			flag=1;
			break;
		}
	}
	if(flag) break;
  }
  while(T[T[0]]==0&&T[0]>0) T[0]--;
  for(int i = 0;i<=T[0];i++)
  A[i] = T[i];
} 
int main()
{
  string s1,s2;
  cin>>s1>>s2;
  num1[0] = s1.size();
  num2[0] = s2.size();
  
  for(int i =1;i<=num1[0];i++)
  num1[i] = s1[num1[0]-i]-'0';
  
  for(int i =1;i<=num2[0];i++)
  num2[i] = s2[num2[0]-i]-'0';
  
  int endnum[2020];
  Sqrt(num1);
  Sqrt(num2);
  CF(endnum,num1,num2);           //乘法 
  for(int i = endnum[0];i>=1;i--)
  printf("%d",endnum[i]);
  return 0;		
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值