lqb 2014省赛

矩阵翻硬币

小明先把硬币摆成了一个 n 行 m 列的矩阵。
随后,小明对每一个硬币分别进行一次 Q 操作。
对第x行第y列的硬币进行 Q 操作的定义:将所有第 ix 行,第 jy 列的硬币进行翻转。
其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。
当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。
小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。
聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。

  • :Segmentation fault
#include<iostream>
using namespace std;
int f[10^1000][10^1000];
int dp[10^1000];

int main()
{
	int target=0;
	int N,M;
	cin>>N>>M;
	int A;
	A=max(N,M);
	
	for(int a=1;a<=A;a++)
	{
	    for(int i=1;i<=a;i++)
	    {
	        if(a%i==0)
	        dp[a]++;
	    }
	}
	for(int n=1;n<=N;n++)
		for(int m=1;m<=M;m++)
		{
			f[n][m]=dp[n]*dp[m];
			if(f[n][m]%2==1)
				target++;
		}
	cout<<target<<endl;
	
	return 0;	
}

有个愚蠢的人想用常规方法解决这个问题,奈何数据量太大,超时又溢出(int = long int = 231-1=2* 1010 ;long long int 263-1=9*1018),甚至还考虑用DP,笑死,根本用不了···

    #include <iostream>
    #include <algorithm>
    using namespace std;
    string StrMul(string s1,string s2)//大数乘法
    {  
        string ans;
        int num[500]={0},i,j;
        for(i=0;i<s1.length();i++)//s计算存到num中
            for(j=0;j<s2.length();j++) 
                num[i+j+1]+=(s1[i]-'0')*(s2[j]-'0');
        for(i=s1.length()+s2.length()-1;i>0;i--)//num的处理    
            if(num[i]>=10)
            {
                num[i-1]+=num[i]/10;
                num[i]%=10;
            }
        for(int i=0;i<=s1.length()+s2.length()-1;i++)//将num数存到ans字串中,注意进位为0的情况
            if(!i&&num[i]||i)
                ans.push_back(num[i]+'0');
        return ans;
    }
    bool StrCmp(string s1,string s2,int pos)//比较两字符串大小,pos代表应该在s1后面填几个零
    {
        if(s1.length()+pos!=s2.length())//如果s1位数不等于s2,
            return s1.length()+pos>s2.length();
        else//位数相等
            return s1>s2;
     } 
    string SqrtStr(string s)//大数平方根取整
    {
        int len;
        string ans;
        if(s.length()%2==0)//长度为偶数
            len=s.length()/2;
        else
            len=s.length()/2+1;
        for(int i=0;i<len;i++)//一位一位的循环
        {
            ans.push_back('0');
            for(int j=0;j<=9;j++)
            {
                if(StrCmp(StrMul(ans,ans),s,2*(len-1-i)))//需要添加0的个数是2*(len-1-i)解析见上面
                    break;
                ans[i]++;
            }
            ans[i]--;
        }
        return ans;
    }
    int main()
    {
        string s1,s2;
        cin>>s1>>s2;
        cout<<StrMul(SqrtStr(s1),SqrtStr(s2))<<endl;
        return 0;
    }

注意到,完全平方数有奇数个约数。同时,小于等于n的完全平方数的个数为[sqrt(n)]个,即为n的平方根向下取整。
问题转化为 解决大数的乘法平方根取整

大数乘法:运用数组,对各位上的数字对应相乘对应相加。

大数平方根取整:
1.如果第i个数的平方的位数加上需要添加个零之后位数与原数不相等,那么位数大的数值大
2.如果位数相等就没必要再添零,直接进行字符串比较即可

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值