蓝桥杯历年试题 矩阵翻硬币

问题描述
  小明先把硬币摆成了一个 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个棋子它的最终状态取决与1-x约数个数的奇偶,而只有平方数的约数个数是奇数,所以转变成求1-n中平方数个数,如果有k个平方数,最大的平方数为k^2,k^2<=n,所以k为sqrt(n)取整。
拓展到二维原理是一样的,只不过需要同时满足x,y均为平方数,那么这样的数的个数即为(1-n的平方数个数)*(1-m的平方数个数)。
观察一下题目的数据范围,上高精度,扔模板。
#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#define LL long long int
using namespace std;
struct numlist
{
    static const int L=1100;
    int a[L];
    int len;
    void ini(string s)//字符串输入
    {
        fill(a,a+L,0);
        for(int i=s.length()-1;i>=0;i--)
            a[s.length()-i-1]=s[i]-'0';
        len=s.length();
    }
    void ini(long long int num)//数字输入
    {
        fill(a,a+L,0);
        len=0;
        if(num==0) len++;
        while(num)
        {
            a[len++]=num%10;
            num/=10;
        }
    }
    void updateBit()//更新位数,约定0的位数是0
    {
        len=0;
        for(int i=0; i<L; i++)
        {
            if(a[i]!=0)
                len=i+1;
            if(a[i]>=10)
            {
                int temp=a[i]/10;
                a[i]%=10;
                a[i+1]+=temp;
            }
            if(a[i]<0)
            {
                int temp=-(a[i]%10!=0)+a[i]/10;
                a[i]%=10;
                if(a[i]<0) a[i]+=10;
                a[i+1]+=temp;
            }
        }
    }
    void print()//测试输出
    {
        for(int i=len-1;i>=0;i--)
            cout<<a[i];
        cout<<endl;
        /*
        for(int i=len-1;i>=0;i--)
            printf("%d",a[i]);
        printf("\n");
        */
    }
};
numlist Add(numlist a,int num)
{
    int p=0;
    while(num)
    {
        a.a[p++]+=num%10;
        num/=10;
    }
    a.updateBit();
    return a;
}
numlist Add(numlist a,numlist b,int f)
{
    int mx=a.len;
    if(b.len>mx) mx=b.len;
    for(int i=0;i<mx;i++)
        a.a[i]+=b.a[i]*f;
    a.updateBit();
    return a;
}
int fix=0;
numlist Bmut(numlist a,numlist b)
{
    numlist c;
    c.ini(0);
    for(int i=0; i<a.len; i++)
        for(int j=0; j<b.len; j++)
            c.a[i+j]+=a.a[i]*b.a[j];

    c.updateBit();
    return c;
}
int BitCmp(numlist a,numlist b)//1:a>b,-1:a<b,0:a==b
{
    if(a.len!=b.len)
        return a.len>b.len?1:-1;
    for(int i=a.len-1;i>=0;i--)
        if(a.a[i]!=b.a[i])
            return a.a[i]>b.a[i]?1:-1;
    return 0;
}
numlist Sqrt(numlist a)
{
    numlist rec,num100,high,preBit;
    num100.ini(100);
    string ans="";//顺序记录每一位
    int pos=a.len-(!(a.len%2)+1);
    numlist temp;
    int initNum=0;
    for(int i=a.len-1;i>=pos;i--)
        initNum*=10,initNum+=a.a[i];

    ans+=sqrt(initNum)+'0';
    preBit.ini(ans);
    initNum-=(int)sqrt(initNum)*(int)sqrt(initNum);
    //cout<<initNum<<endl;
    temp.ini(initNum);//部分余数
    pos-=2;
    for(;pos>=0;pos-=2)
    {
        ans+='0';
        for(int i=preBit.len;i>0;i--)
            preBit.a[i]=preBit.a[i-1];
        preBit.a[0]=0;
        preBit.len++;

        high=preBit;
        high=Add(high,high,1);
        temp=Bmut(temp,num100);
        temp=Add(temp,a.a[pos]+a.a[pos+1]*10);
        numlist pn,pn1;
        numlist pnow,ppre;
        int p=5;
        do
        {
            pn.ini(p),pn1.ini(p-1);

            pnow=Bmut(Add(high,p),pn);

            ppre=Bmut(Add(high,p-1),pn1);
            if(BitCmp(temp,ppre)<0)
                p--;
            else if(BitCmp(pnow,temp)<=0)
                p++;
            else
                break;
        }while(1);
        p--;
        preBit.a[0]=p;
        pn.ini(p);
        pnow=Bmut(Add(high,p),pn);
        temp=Add(temp,pnow,-1);
        ans[ans.length()-1]=p+'0';
        //cout<<"---"<<endl;
    }
    rec.ini(ans);
    return rec;
}
int main()
{
    string a,b;
    while(cin>>a>>b)
    {

        numlist ax,bx;
        ax.ini(a);
        bx.ini(b);
        Bmut(Sqrt(ax),Sqrt(bx)).print();
        //Add(temp,-5);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/LukeStepByStep/p/6387472.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值