蓝桥杯PREV-34(数论+大数相乘大数开方模板)

思路:要推出一开始有多少枚硬币反面朝上,我们从最终全部正面朝上开始出发,对每个位置进行Q操作得出初态。然后现在来考虑,对于任意一枚正面朝上的硬币,经过奇数次的反转,肯定变为反面朝上。所以只要计算经过奇数次反转的硬币就可以得出答案了。接下来要做就是对于某一个位置的硬币(x,y)它的反转次数的奇偶如何确定呢。手动模拟可以得出结论:能影响到(x,y)反转的是(i,j)(i,j分别是x和y的约数)。组合起来一共有i*j次反转。而反转为奇数,即i*j为奇数,当且仅当i  j都为奇数。接下来问题就变成在m*n的矩阵中分别找出行、列编号有奇数个约数的个数,相乘即为所求。(一个数的约数个数为奇数,这个数是一个完全平方数,且 1-n内的完全平方数个数为sqrt(n)),所以最后结果为sqrt(n)*sqrt(m) 不过由于数据巨大,这里要用到大数相乘和开方。

不过比赛的时候是不可以带模板的,大数相乘就GG了,直接用sqrt 和*能得40分。嗯,比赛时也不错了。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
using namespace std;
long long n,m,cnt;
string s1,s2;

string strMul(string a,string b)
{
	string result="";
	int len1=a.length();
	int len2=b.length();
	int i,j;
	int num[500]={0};
	for(i=0;i<len1;i++)
	for(j=0;j<len2;j++)
	{
		num[len1-1+len2-1-i-j]=num[len1-1+len2-1-i-j]+(a[i]-'0')*(b[j]-'0');
	}

	//for(i=0;i<5;i++)
	//cout<<num[i]<<' ';
	//cout<<endl;

	for(i=0;i<len1+len2;i++)
	{
		num[i+1]=num[i+1]+num[i]/10;
		num[i]=num[i]%10;
	}

	//for(i=0;i<5;i++)
	//cout<<num[i]<<' ';

	for(i=len1+len2-1;i>=0;i--)
	{
		if(num[i]!=0)
		break;
	}
	for(;i>=0;i--)
	{
		result=result+(char)(num[i]+'0');
	}
	return result;
}

int strCmp(string a,string b,int pos)
{
	int i;
	//cout<<a<<endl;
	//cout<<a.length()<<' '<<b.length()<<endl;
	if(a.length()+pos>b.length())
	return 1;
	if(a.length()+pos<b.length())
	return 0;
	if(a.length()+pos==b.length())
	{
		for(i=0;i<a.length();i++)
		{
			if(a[i]<b[i])
			return 0;
			if(a[i]==b[i])
			continue;
			if(a[i]>b[i])
			return 1;
		}

	}
}

string strSqrt(string a)
{
	string result="";
	int i;
	int len=a.length();
	if(len%2==0)
	len=len/2;
	else
	len=len/2+1;
	for(i=0;i<len;i++)
	{
		result=result+'0';
		while(strCmp(strMul(result,result),a,2*(len-1-i))!=1)
		{
			if(result[i]==':')
			break;
			result[i]++;
		}
		result[i]--;
	}
	return result;
}

int main(){
    while(cin>>s1>>s2){
        cout<<strMul(strSqrt(s1),strSqrt(s2))<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值