0
点赞
收藏
分享

微信扫一扫

(自娱自乐)构造题练习笔记

GG_lyf 2022-04-14 阅读 171
算法

Codeforces Round #781 (Div. 2) D. GCD Guess

题目需要求出x,每次操作知道(x+a,x+b);

先假设d=(x+a,x+b),每次我们可以构造出一个同余式x=-a(mod d)

不难发现我们只要构造出足够多的同余式就可以用excrt搞定。

那么怎么选取a就很关键了,或者我们可以试着去构造出一个巧妙的lcm(d1,d2,..dk),并且保证lcm的值大于x的取值范围。

不难发现只需要选取从2到29的质因子就能凑齐大于1e9的lcm,但或许不需要选取那些质因子并且将会更优,虽然也没什么区别就是了。这里是取的d是4,5,7,9,11,13,17,19,23;然后lcm就是1338557220。

同时我们把b成lcm+a。这样保证了,对于x+a的因子,一定也是lcm的因子,这样才能保证excrt的模数范围

我们想要所有的gcd(x+a,x+lcm+a)都是这些d之间的积,那么我们需要保证x+a一定并且至少是一个d的倍数。

我们把目光投向最大的d:23。这个时候我们只需要保证取遍模23的剩余系就好了,另a=1-23,一定有一个数字加上x是23的倍数。

因此就构造出来了一种解法。只需要在写程序之前计算出一组lcm,然后令a取遍最大的d范围内所有数,之后就交给excrt好了

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=35,N=1e5+10,inf=2e9;
const long long Lcm=1338557220;
ll get(ll a,ll b)
{
    printf("? %lld %lld\n",a,b);fflush(stdout);
    ll d;scanf("%lld",&d);
    return d;
}
ll a[maxn],m[maxn];
int n=23;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0)
    {
        return x=1,y=0,a;
    }
    ll d=exgcd(b,a%b,y,x);
    y-=a/b*x;return d;
}
ll mul(ll a,ll b,ll mod)
{
    ll res=0;
    while(b>0)
    {
        if(b&1) res=(res+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return res;
}
ll excrt()//扩展中国剩余定理
{
    ll m1,a1,x,y,bg;
    m1=m[1],a1=a[1];
    for(int i=2;i<=n;i++)
    {
 
        ll m2=m[i],a2=a[i],c=((a2-a1)%m2+m2)%m2;
        ll d=exgcd(m1,m2,x,y);
        //if(c%d){return -1;}
       // if(mul(x,c/d,m2/d)<=0)continue;
        x=mul(x,c/d,m2/d);
        a1=x*m1+a1;
        m1=m2/d*m1;
        a1=(a1%m1+m1)%m1;
    }
    a1=(a1%m1+m1)%m1;
    if(a1==0)a1=m1;
    return a1;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        ll x,y;
         ll d;
        for(int i=1;i<=n;i++)
        {
            x=i,y=Lcm+i;
             d=get(x,y);
            m[i]=d;a[i]=d-x%d;
        }
        printf("! %lld\n",excrt()%Lcm);
        fflush(stdout);
    }
}
举报

相关推荐

0 条评论