zoukankan      html  css  js  c++  java
  • qbxt 10 月模拟赛 Day6

    A

    假设 (a geq b)

    [egin{aligned} gcd(q^a-q,q^b-1) &= gcd(q^b-1,q^a-q^b)\ &= gcd(q^b-1,q^b(q^{a-b}-1))\ &= gcd(q^b-1,q^{a-b}-1) end{aligned} ]

    使用取模加速运算即可。本质是对指数辗转相除。

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    int q,a,b,ha;
    
    inline int qpow(int a,int n=ha-2){
    	int res = 1;
    	while(n){
    		if(n & 1) res = 1ll*res*a%ha;
    		a = 1ll*a*a%ha;
    		n >>= 1;
    	}
    	return res;
    }
    
    inline int gcd(int a,int b){
        if(a < b) return gcd(b,a);
        if(!b) return (qpow(q,a)+ha-1)%ha;
        return gcd(b,a%b);
    }
    
    int main(){
        int T;scanf("%d",&T);
        while(T--){
            scanf("%d%d%d%d",&q,&a,&b,&ha);
            LL x = qpow(q,a)-1,y = qpow(q,b)-1;
            printf("%d
    ",gcd(a,b));
        }
        return 0;
    }
    

    B

    开 1e6 个 vector 存一下所有的倍数,每次取出最少的,如果数量变成 (0) 了就弹掉。

    复杂度 (O(n log n))

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 1e6 + 5;
    
    inline char nc(){
        #define SIZE 1000000+3
        static char buf[SIZE],*p1 = buf+SIZE,*p2 = buf+SIZE;
        if(p1 == p2){
            p1 = buf;p2 = buf+fread(buf,1,SIZE,stdin);
            if(p1 == p2) return -1;
        }
        return *p1++;
        #undef SIZE
    }
    
    template <typename T>
    inline void read(T &x){
        x = 0;int flag = 0;char ch = nc();
        while(!isdigit(ch)){
            if(ch == '-') flag = 1;
            ch = nc();
        }
        while(isdigit(ch)){
            x = (x<<1) + (x<<3) + (ch^'0');
            ch = nc();
        }
        if(flag) x = -x;
    }
    
    bool p[MAXN];
    int prime[MAXN],tot,d[MAXN];
    
    inline void prework(){
        FOR(i,2,MAXN-1){
            if(!p[i]) prime[++tot] = i,d[i] = i;
            for(int j = 1;j <= tot && 1ll*i*prime[j] < MAXN;++j){
                p[i*prime[j]] = 1;d[i*prime[j]] = prime[j];
                if(!(i%prime[j])){
                    d[i*prime[j]] = d[i];
                    break;
                }
            }
        }
    }
    
    int a[MAXN],n,m,cnt[MAXN];
    std::vector<int> dec[MAXN];
    int pp[MAXN],ee[MAXN],sz;
    
    inline void dfs(int dep,int id,int sm=1){
        if(dep == sz+1){
            dec[id].pb(sm);
            return;
        }
        dfs(dep+1,id,sm);
        FOR(i,1,ee[dep]) sm *= pp[dep],dfs(dep+1,id,sm);
    }
    
    inline void fj(int i){
        if(i == 1){
            dec[1].pb(1);
            return;
        }
        int x = i,las = d[x];x /= d[x];
        sz = 0;int cnt = 1;
        while(x != 1){
            if(las != d[x]){
                ++sz;
                pp[sz] = las;
                ee[sz] = cnt;
                las = d[x];cnt = 0;
            }
            x /= d[x];cnt++;
        }
        ++sz;pp[sz] = las;ee[sz] = cnt;
        dfs(1,i);
    }
    
    std::vector<int> G[MAXN];
    
    int main(){
        prework();
        read(n);
        FOR(i,1,n) read(a[i]),++cnt[a[i]];
        ROF(i,MAXN-1,1){
            if(cnt[i]){
                fj(i);
                for(auto x:dec[i]) G[x].pb(i);
            }
        }
        read(m);std::vector<int> ans;
        FOR(i,1,m){
            int x;read(x);
            while(!G[x].empty() && !cnt[G[x].back()]) G[x].pop_back();
            if(G[x].empty()) break;
            int v = G[x].back();
            ans.pb(v);cnt[v]--;
        }
        printf("%d
    ",(int)ans.size());
        for(auto x:ans) printf("%d ",x);puts("");
        return 0;
    }
    

    C

    拆式子:

    [egin{aligned} &sum_{i=1}^n sum_{j=i+1}^n A_i^2B_j^2+A_j^2B_i^2-A_iA_jB_iB_j\ &= (sum_{i=1}^n A_i^2)(sum_{j=1}^n B_j^2) - (sum_{i=1}^n A_iB_i)^2\ end{aligned} ]

    树状数组分开维护就好了。

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 5e5 + 5;
    const int ha = 998244353;
    const int inv2 = 499122177;
    
    inline void add(int &x,int y){
        x += y;if(x >= ha) x -= ha;
    }
    
    int a[MAXN],b[MAXN];
    
    inline char nc(){
        #define SIZE 1000000+3
        static char buf[SIZE],*p1 = buf+SIZE,*p2 = buf+SIZE;
        if(p1 == p2){
            p1 = buf;p2 = buf+fread(buf,1,SIZE,stdin);
            if(p1 == p2) return -1;
        }
        return *p1++;
        #undef SIZE
    }
    
    template <typename T>
    inline void read(T &x){
        x = 0;int flag = 0;char ch = nc();
        while(!isdigit(ch)){
            if(ch == '-') flag = 1;
            ch = nc();
        }
        while(isdigit(ch)){
            x = (x<<1) + (x<<3) + (ch^'0');
            ch = nc();
        }
        if(flag) x = -x;
    }
    
    struct BIT{
        #define lowbit(x) ((x)&(-(x)))
        int tree[MAXN];
    
        inline void add(int pos,int x){
            while(pos < MAXN){
                ::add(tree[pos],x);
                pos += lowbit(pos);
            }
        }
    
        inline int calc(int pos){
            if(!pos) return 0;
            int res = 0;
            while(pos){
                ::add(res,tree[pos]);
                pos -= lowbit(pos);
            }
            return res;
        }
    
        inline int query(int l,int r){
            return (calc(r)+ha-calc(l-1))%ha;
        }
    }bit1,bit2,bit3;
    
    int n,q;
    
    int main(){
        read(n);read(q);
        FOR(i,1,n) read(a[i]),bit1.add(i,1ll*a[i]*a[i]%ha);
        FOR(i,1,n) read(b[i]),bit2.add(i,1ll*b[i]*b[i]%ha);
        FOR(i,1,n) bit3.add(i,1ll*a[i]*b[i]%ha);
        FOR(i,1,q){
            int opt;read(opt);
            if(opt == 1){
                int l,r;read(l);read(r);
                int a = bit1.query(l,r),b = bit2.query(l,r),c = bit3.query(l,r);
                int res = (1ll*a*b%ha+ha-1ll*c*c%ha)%ha;
                printf("%d
    ",res);
            }
            else{
                int p;read(p);
                bit1.add(p,ha-1ll*a[p]*a[p]%ha);
                bit2.add(p,ha-1ll*b[p]*b[p]%ha);
                bit3.add(p,ha-1ll*a[p]*b[p]%ha);
                read(a[p]);read(b[p]);
                bit1.add(p,1ll*a[p]*a[p]%ha);
                bit2.add(p,1ll*b[p]*b[p]%ha);
                bit3.add(p,1ll*a[p]*b[p]%ha);
            }
        }
        return 0;
    }
    

    D

    这个题循环是假的,实际是给定了一些不等式关系,要求你确定有多少组解。

    我们只关心相对大小关系;如果相对大小关系不同方案绝对不同,相对大小关系也决定了有多少组数是相等的。

    所以设 (f_{i,S}) 表示从小到大选出了 (i) 组,已经用了 (S) 内的数的方案数,每次枚举一个子集,要满足 (S) 内的数都不能大于这个子集内的数,转移即可。

    然后就可以用组合数计算答案了。这里注意到 (m) 很小,可以手动约分。(居然之前没注意过)

    加强

    复杂度可以做到 (O(n^2 cdot 2^n))

    做法是我们首先缩点,发现一个 SCC 内的点一定同时选,于是图变成了 DAG ,选择方案合法当且仅当当前选出的集合没有指向之前集合的边。。所以还要设 (f_{i,j,S}) 表示考虑到第 (i) 个点,用了 (j) 个集合,选择了 (S) 内的点,然后转移枚举这个是否要新建集合。。

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 15 + 1;
    
    int n,m,ha;
    
    inline void add(int &x,int y){
        x += y;if(x >= ha) x -= ha;
    }
    // a < b : a -> b
    int small[(1<<MAXN)+3],big[(1<<MAXN)+3];
    int f[MAXN][(1<<MAXN)+3];
    // 选出了 S 内 i 组,组内相同的方案数
    // 每次从小到大划分组
    
    int tmp[MAXN];
    
    inline int C(int n,int m){
        if(n < m) return 0;
        FOR(i,1,m) tmp[i] = n-i+1;
        FOR(i,2,m){
            int x = i;
            FOR(j,1,m){
                int g = std::__gcd(tmp[j],x);
                x /= g;tmp[j] /= g;
            }
        }
        int ans = 1;
        FOR(i,1,m) ans = 1ll*ans*tmp[i]%ha;
        return ans;
    }
    
    int main(){
        scanf("%d%d%d",&m,&n,&ha);//ha = 998244353;
        FOR(i,0,m-1){
            int k;scanf("%d",&k);
            while(k--){
                int x;scanf("%d",&x);--x;
                small[1<<i] |= (1<<x);
                big[1<<x] |= (1<<i);
            }
            scanf("%d",&k);
            while(k--){
                int x;scanf("%d",&x);--x;
                small[1<<x] |= (1<<i);
                big[1<<i] |= (1<<x);
            }
        }
        FOR(S,0,(1<<m)-1){
            FOR(i,0,m-1){
                if((S>>i)&1){
                    small[S] |= small[S^(1<<i)];
                    big[S] |= big[S^(1<<i)];
                }
            }
        }
        f[0][0] = 1;
        FOR(i,0,m-1){
            FOR(S,0,(1<<m)-1){
                if(!f[i][S]) continue;
                int s = ((1<<m)-1)^S;
                for(int T = s;T;T = (T-1)&s){
                    if(((big[T]&S) == 0)){
                        add(f[i+1][S^T],f[i][S]);
                    }
                }
            }
        }
        int ans = 0;
        FOR(i,1,m) (ans += 1ll*C(n,i)*f[i][(1<<m)-1]%ha) %= ha;
        printf("%d
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    android之Activity回传数据
    Android之Activity启动模式
    桥接模式
    Android之Activity跳转
    Android多线程文件下载
    代理模式
    适配器模式
    vs2010 入门程序
    文件动态打开获取数据
    项目测试一 批量读取数据到数组
  • 原文地址:https://www.cnblogs.com/rainair/p/14305836.html
Copyright © 2011-2022 走看看