codeforces #271E Three Horses 数论

本文介绍了一种关于卡片组合的算法问题,通过分析三种操作对卡片数值的影响,推导出能够获得目标卡片组合的条件,并给出具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:有一种卡片,正面和背面各写着一个整数,可以用一个有序数对(x,y)表示
有三种操作:
1.出示一张卡片(x,y),获得一张卡片(x+1,y+1)
2.出示一张卡片(x,y)(x,y都是偶数),获得一张卡片(x2,y2)
3.出示两张卡片(x,y)(y,z),获得一张卡片(x,z)
一个人想要卡片(1,a1),(1,a2),(1,a3),...,(1,an),他可以携带一张初始卡片(x,y)(1x<ym),求有多少种方案

首先我们发现:
第一个操作不改变yx的值
第二个操作可以使yx变为原来的12
第三个操作可以使yx变为原来的任意倍

那么我们不妨猜想:一张卡片(x,y)是否合法只与yx的值有关

事实上这个是正确的

结论:卡片(x,y)满足条件当且仅当yxgcd(a11,a21,...,an1)的一个约数d2k

证明:

必要性:
不妨设yx=d2k(d为奇数),那么由上面的三个性质可知,所有能凑出的卡片的差值必为d的倍数
故如果d不是ai1的约数,则一定无法凑出卡片(1,ai)
必要性得证

充分性:
不妨设yx=d2k(d为奇数且d|gcd(a11,a21,...,an1))
我们任选一个k,满足k>=k2kx
那么首先我们利用(x,y)不断执行操作1和操作3得到(x,x+d2k)
然后我们利用操作1得到(2k,(1+d)2k)
然后进行k次操作2得到(1,1+d)
至此我们已经得到了(1,1+d),再不断进行操作1和操作3就能得到所有卡片了

证毕

然后就好办了,我们枚举gcd(a11,a21,...,an1)的每个奇约数d,然后枚举d2kO(1)
时间复杂度O(d(ai)logm)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 2020
using namespace std;
int n,m,gcd;
long long ans;
int divisor[M],tot;
void Get_Divisor(int n)
{
    int i;
    for(i=1;i*i<n;i++)
        if(n%i==0)
        {
            divisor[++tot]=i;
            divisor[++tot]=n/i;
        }
    if(i*i==n)
        divisor[++tot]=i;
}
int main()
{
    int i,j,x;
    cin>>n>>m;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&x);
        gcd=__gcd(gcd,x-1);
    }
    Get_Divisor(gcd);
    for(i=1;i<=tot;i++)
        if(divisor[i]&1)
            for(j=divisor[i];j<=m;j<<=1)
                ans+=m-j;
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值