codeforces #271E Three Horses 数论

题目大意:有一种卡片,正面和背面各写着一个整数,可以用一个有序数对 (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) 满足条件当且仅当 yx gcd(a11,a21,...,an1) 的一个约数 d 2k

证明:

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

充分性:
不妨设 yx=d2k(d 为奇数且 d|gcd(a11,a21,...,an1))
我们任选一个 k ,满足 k>=k 2kx
那么首先我们利用 (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 ,然后枚举 d2k O(1)
时间复杂度 O(d(ai)logm)

#include 
#include 
#include 
#include 
#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*iif(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<return 0;
}

你可能感兴趣的:(其它题库,数论)