Codeforces 1339E Perfect Triples (找规律)

题意

构造了一个数组,其中每相邻三个数(a,b,c)为一组,满足a<b<c,且abc==0,数组字典序最小并且没有重复的数
1e5组询问,问你第n项是多少,n<=1e15

思路

果断打表,每组分开看,发现单看a是一个第i组开头为\(4^{i-1}\),长度为\(4^{i-1}\)的序列
而b的规律就比较难看了,由于题目中的异或可以想到打下二进制的表
发现b的二进制中每两位与对应的a的二进制每两位呈映射关系
a与b:0对应0,1对应2,2对应3,3对应1
然后对于每次询问我们只需要O(30)得到a的值,继而可以得到b,c

代码

这种规律我是想不到的

ll po[55];
ll s(int x){
    if(x==0)return 0;
    return (po[x]-1)/3;
}
int main(){
    int t;
    po[0]=1;
    for(int i = 1; i <= 31; i++)po[i]=po[i-1]*4;
    scanf("%d", &t);
    while(t--){
        ll n;
        scanf("%lld", &n);
        ll id = (n+2)/3;
        ll now;
        for(int i = 1; i <= 31; i++){
            if((po[i]-1)/3>=id){
                now=i;break;
            }
        }
        ll x = po[now-1]+id-s(now-1)-1;
        vector<int>v;
        ll X = x;
        while(X){
            v.pb(X%4);X/=4;
        }
        ll y = 0;
        reverse(v.begin(),v.end());
        for(auto &xx:v){
            if(xx==1)xx=2;
            else if(xx==2)xx=3;
            else if(xx==3)xx=1;
            y*=4;y+=xx;
        }
        if(n%3==1){
            printf("%lld\n",x);
        }
        else if(n%3==2){
            printf("%lld\n",y);
        }
        else printf("%lld\n",x^y);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wrjlinkkkkkk/p/12693729.html