Try Again

蓝桥杯 矩阵翻硬币

问题描述
  小明先把硬币摆成了一个 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次方)。
解题思路:确定x,y,找i,j值,及是x,y的倍数是都会被翻转,及一个点(a,b)被翻转多少次取决于a,b的约数的个数。又因为还原之后回到最初的状态,及f(a)*f(b)为奇数(设f(x)为x的约数的个数)首先可以确定的是一个数的其中一个约数一定可以找到一个数使得两者乘积为x,若想约数为计数,只能使得某两个约数相等,所以就只有完全平方数符合条件。而1~n之中,完全平方数的个数为sqrt(n),所以此题转化为求sqrt(n)*sqrt(m),题目要求,n,m<=10^1000,显然,大数乘法。(Java大数开根,自己的丑代码    
BZOJ高精度开根     )现在,学习一下C++实现。
大数乘法:由于数字无法用一个整形变量存储,很自然的想到用字符串来表示一串数字。然后按照乘法的运算规则,用一个乘数的每一位乘以另一个乘数,然后将所有中间结果按(i+j)相同累加得到最终结果。可以分析得出如果乘数为A和B,A的位数为m,B的位数为n,则乘积结果为m+n-1位(最高位无进位)或m+n位(最高位有进位)。因此可以分配一个m+n的辅存来存储最终结果。为了节约空间,所有的中间结果直接在m+n的辅存上进行累加。以"18"*"36"a[0]*b[0]=1*3=3,a[0]*b[1]=6,a[1]*b[0]=24,a[1]*b[1]=48;所以c[0+0]=3,c[0+1]=30,c[1+1]=48;最终进位得到648
大数开根:一个n位数开方的位数满足下列条件:
    m=n/2(n为偶数)
    m=n/2+1(n为奇数)
如此通过确定平方根的位数假设为xyz形式,从最高位开始从0~9遍历使得x00^2<n<(x+1)00^2,
然后降位依次逼近。例如求sqrt(356),平方根为两位
10^2<356
20^2>356
所以高位为1,然后确定个位
11^2=121<356;
12^2=144<356
...
18^2=324<356
19^2=361>356
所以sqrt(356)=18;
//大数乘法开跟C++版
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cstdlib>
#include <iomanip>
#include <cmath>
#include <cassert>
#include <ctime>
#include <map>
#include <set>
using namespace std;
#pragma comment(linker, "/stck:1024000000,1024000000")
#define lowbit(x) (x&(-x))
#define max(x,y) (x>=y?x:y)
#define min(x,y) (x<=y?x:y)
#define MAX 100000000000000000
#define MOD 1000
#define pi acos(-1.0)
#define ei exp(1)
#define PI 3.1415926535897932384626433832
#define ios() ios::sync_with_stdio(true)
#define inf 0x3f3f3f3f
#define mem(a) (memset(a,0,sizeof(a)))
typedef long long ll;
string n,m;
string strmul(string a,string b)
{
    string result="";
    int a_len=a.length();
    int b_len=b.length();
    int ans[1006];
    memset(ans,0,sizeof(ans));
    for(int i=0;i<a_len;i++)
    {
        for(int j=0;j<b_len;j++)
        {
            ans[a_len-1+b_len-1-i-j]+=(a[i]-'0')*(b[j]-'0');
        }
    }
    for(int i=0;i<a_len+b_len;i++)
    {
        ans[i+1]=ans[i+1]+ans[i]/10;
        ans[i]%=10;
    }
    int k;
    for(k=a_len+b_len;k;k--)
    {
        if(ans[k]) break;
    }
    for(k;k>=0;k--)
        result+=(char)('0'+ans[k]);
    return result;
}
int strCpy(string a,string b,int ans)
{
    if(a.length()+ans>b.length()) return 1;
    else if(a.length()+ans<b.length()) return 0;
    else
    {
        for(int i=0;i<a.length();i++)
        {
            if(a[i]>b[i]) return 1;
            else if(a[i]<b[i]) return 0;
            else continue;
        }
    }
}
string strsqrt(string a)
{
    int len;
    string result;
    if(a.length()%2==0) len=a.length()/2;
    else len=a.length()/2+1;
    for(int i=0;i<len;i++)
    {
        result+='0';
        while(!strCpy(strmul(result,result),a,2*(len-1-i)))
        {
            if(result[i]==':') break;
            result[i]++;
        }
        result[i]--;
    }
    return result;
}
int main()
{
    cin>>n>>m;
    cout<<strmul(strsqrt(n),strsqrt(m));
    return 0;
}

 

 
 

 
 
posted @ 2018-03-16 20:40  十年换你一句好久不见  阅读(341)  评论(0编辑  收藏  举报