zoukankan      html  css  js  c++  java
  • 7.10模拟赛

     (题目在文末)

    T1.qiang

    不写逆元见祖宗..

    首先一个合法方案最少要包含一个形如1,2,3,..n的数列,再考虑在其中插入一些数。

    考虑以x结尾的一种方案,x贡献了了num[x]次,在初始序列中出现了一次,所以贡献了num[x]-1次,其中的每一种,都有sum[x]-1个地方可以放(至少放在x前,不然就违背了定义)

    所以答案就是π(C(sum[i]-1,num[i]-1))(之前都想得很正常,接下来开始表演爆0)

    具体计算组合数时,显然要预处理阶乘,然而这里有乘法,所以要用逆元(这不是显然吗,我的脑子呢..)

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    const int MAXN=500005;
    const int N=500000;
    
    const int MOD=998244353;
    
    typedef long long ll;
    
    inline ll rd(){
        ll ret=0,f=1;char c;
        while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
        while(isdigit(c))ret=ret*10+c-'0',c=getchar();
        return ret*f;
    }
    
    
    
    ll po(ll x,ll y) {
        ll ret=1,base=x;
        while(y) {
            if(y&1) (ret*=base)%=MOD;
            (base*=base)%=MOD;
            y>>=1;
        }
        return ret;
    }
    
    ll fac[MAXN],inv[MAXN];
    
    void prework() {
        fac[0]=1;
        for(int i=1; i<=N; i++) fac[i]=(fac[i-1]*i)%MOD;
        inv[N]=po(fac[N],MOD-2);
        for(int i=N-1; i>=0; i--) inv[i]=(inv[i+1]*(i+1))%MOD;
    }
    
    inline ll C(ll x,ll y){
        if(y>x) return 0;
        return (1ll*(fac[x]*inv[y])%MOD*inv[x-y])%MOD;
    }
    
    ll ans=1;
    ll n;
    ll num[MAXN],sum[MAXN];
    
    int main() {
        prework();
        n=rd();
        for(int i=1;i<=n;i++) num[i]=rd(),sum[i]=sum[i-1]+num[i];
        for(int i=1;i<=n;i++){
            ans*=C(sum[i]-1,num[i]-1);
            ans%=MOD;
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code

     T2.count

    30分:朴素状压 O(4*T*(2^n))

    60分:行列交换之后状压,复杂度O(T*n*256) (数据水,其实这里就能拿100分了)

    100分:对于状压的两个可行状态i和j,且i可以向j转移,那么在i和j之间连边,把原问题转化为在图上走n步到达制定状态的问题。

    邻接矩阵存图,矩阵乘法。

    或者是归纳出一个神奇的公式f(n)=f(n-1)+5*f(n-2)+f(n-3)-f(n-4)

    60分做法:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    
    using namespace std;
    
    int f[100005][18];
    
    const int UP=(1<<4)-1;
    
    bool legal[32];
    int n,m;
    
    void prework(){
        for(int i=0;i<=UP;i++){
            int cnt=0,succ=0;
            for(int j=0;j<4;j++){
                if(i&(1<<j)) {if(cnt&1) break;cnt=0;}
                else cnt++;
            }
            succ=1;
            if(cnt&1) continue;
            legal[i]=succ;
        }
    }
    
    int main(){
        prework();
        int T;
        while(cin>>n>>m){
            if(!n) return 0;
            memset(f,0,sizeof(f));
            f[0][0]=1;
            for(int i=1;i<=n;i++){
                for(int j=0;j<=UP;j++){
                    if(!legal[j]) continue;
                    for(int k=0;k<=UP;k++){
                        if(!legal[k|j]) continue;
                        if(j&k) continue;
                        f[i][j]+=f[i-1][k];
                        f[i][j]%=m;
                    }
                }
            }
            cout<<f[n][0]<<endl;
        }
        return 0;
    }
        
    View Code

    100分做法:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    
    using namespace std;
    
    const int MAXN=32;
    const int UP=16;
    int MOD;
    
    struct Mat {
        int data[MAXN][MAXN];
        Mat() {memset(data,0,sizeof(data));}
        Mat operator*(const Mat &rhs) {
            Mat ret;
            for(int k=0; k<UP; k++)
                for(int i=0; i<UP; i++)
                    for(int j=0; j<UP; j++)
                        ret.data[i][j]+=data[i][k]*rhs.data[k][j],//
                            ret.data[i][j]%=MOD;
            return ret;
        }
    };
    Mat pow(Mat y,int x) {
        Mat ret,base=y;
        for(int i=0; i<UP; i++) ret.data[i][i]=1;
        while(x) {
            if(x&1) ret=ret*base;
            base=base*base;x>>=1;
        }
        return ret;
    }
    
    int legal[MAXN];
    
    void prework() {
        for(int i=0; i<=UP; i++) {
            int cnt=0,succ=0;
            for(int j=0; j<4; j++) {
                if(i&(1<<j)) {
                    if(cnt&1) break;
                    cnt=0;
                } else cnt++;
            }
            succ=1;
            if(cnt&1) continue;
            legal[i]=succ;
        }
    }
    
    Mat sav,ori;
    int n;
    
    int main() {
        prework();
        for(int i=0; i<UP; i++) {
            for(int j=0; j<UP; j++) {
                if(!legal[i|j]) continue;
                if(i&j) continue;
                ori.data[i][j]=1;
            }
        }
        while(cin>>n>>MOD) {
            if(!n) break;
            Mat tmp=pow(ori,n-1);
            int ans=0;
            for(int i=0; i<UP; i++) if(legal[i]) ans+=tmp.data[0][i];
            cout<<ans%MOD<<endl;
        }
        return 0;
    }
    View Code

     T3.sequence

    理解是这样的,先考虑一个弱化版本,如果不是mod 4意义下呢?

    假设B[i]>A[i],那么每个A[i]需要增加C[i]=B[i]-A[i],不妨处理出这个C[i]

    比如,我们有A[]={0,3,1,2,1},B[]={3,7,8,6,8},那么可以算出C[]={3,4,7,4,7},不妨看成一个柱状图

    区间整体加1,可以看成横向削一层,不难发现答案就是Σmax(0,a[i]-a[i-1])

    这启发我们在考虑mod 4意义下的问题时,也另外考虑一个差分数组d(diff)[i]

    对原区间进行区间加,就是差分数组的单点修改,考虑一个区间[i,j],我们要做的就是d[i]++,d[j]--

    现在就来考虑一下如何贪心地给d[j]寻找一个对应的d[i],使得配对代价最小。

    用一个桶维护前面出现过的数,并只计算正数的贡献(max(0,x)),贪心地从小往大选

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    
    using namespace std;
    
    const int MAXN=1e7+10;
    
    int a[MAXN],b[MAXN],c[MAXN],d[MAXN],s[MAXN];
    int n;
    
    int main(){
        int T;
        cin>>T;
        while(T--){
            cin>>n;
            memset(s,0,sizeof(s));
            for(int i=1;i<=n;i++) cin>>a[i];
            for(int i=1;i<=n;i++) cin>>b[i];
            for(int i=1;i<=n;i++) c[i]=(b[i]-a[i]+4)%4;
            for(int i=1;i<=n;i++) d[i]=c[i]-c[i-1];
            int ans=c[1],j;
            for(int i=2;i<=n;i++){
                s[(d[i]+3)%4+1]++;
                if(d[i]<=0) continue;
                for(j=0;!s[j];j++);
                s[j]--;
                ans+=j;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code

    官方题解


    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9289735.html

  • 相关阅读:
    (转载)正向代理与反向代理的区别
    Java设计模式系列之装饰者模式
    工作中使用到的技术和工具分享
    Springboot+mybatis整合
    云计算入门和实践
    tesseract系列(1) -- tesseract用vs编译成库
    nodepad++ 让所有的加号收缩折叠展开的快捷键
    tesseract系列(4) -- tesseract训练问题总结
    tessereact的链接收藏
    菜鸟cmake使用
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9289735.html
Copyright © 2011-2022 走看看