2018.7.10模拟赛

T1考场上一直想拿那80分,dp推了半天没出来,搜索40分走人。正解是组合数学,倒着考虑,前面有sum[i]-1个位置,每个位置可以放当前i的num[i]-1个,费马小定理+组合数搞。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long

using namespace std;
const int MAXN = 500005;
const int mod = 998244353;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,sum,num[MAXN];
LL ans=1,inv[MAXN],to[MAXN];

inline LL C(int n,int m){
    return to[n]*inv[m]%mod*inv[n-m]%mod;
}

inline LL fast_pow(LL A,int B){
    LL ret=1;
    for(;B;B>>=1){
        if(B&1) ret=ret*A%mod;
        A=A*A%mod;
    }
    return ret;
}

int main(){
    freopen("qiang.in","r",stdin);
    freopen("qiang.out","w",stdout);
    n=rd();
    to[1]=1;
    for(register int i=2;i<=500000;i++) to[i]=to[i-1]*i%mod;
//  cout<<to[MAXN];
    inv[MAXN-5]=fast_pow(to[MAXN-5],mod-2);
//  cout<<inv[MAXN]<<endl;
    for(register int i=499999;~i;i--) inv[i]=inv[i+1]*(i+1)%mod;
    for(register int i=1;i<=n;i++) num[i]=rd(),sum+=num[i];
    for(register int i=n;i;i--){
        LL k=C(sum-1,num[i]-1);
        if(k!=0)
        ans*=k,ans%=mod;
//      cout<<ans<<endl;
        sum-=num[i];
    }
    printf("%lld",ans);
    return 0;
}

T2考场上以为是一个规律题,打表找规律,结果GG,搜索30分滚蛋(我可能是个只会爆搜的蒟蒻)。正解矩阵快速幂,以前做过这种类型的状压题,貌似这次状压就能水60分,

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long

using namespace std;

int n,m;

struct Mat{
    int a[17][17];
    Mat(){
        memset(a,0,sizeof(a));
    }
    Mat operator*(const Mat &h){
        Mat c;
        for(register int i=0;i<16;i++)
            for(register int j=0;j<16;j++)
                for(register int k=0;k<16;k++){
                    c.a[i][j]+=a[i][k]*h.a[j][k]%m;
                    c.a[i][j]%=m;
                }
        return c;
    }
}A,k;

inline bool judge(int x){
    if(x==0 || x==3 || x==9 || x==12 || x==15) return true;
    return false;
}

inline void init(){
    for(register int i=0;i<16;i++)
        k.a[i][i]=1;
    for(register int i=0;i<16;i++)
        for(register int j=0;j<16;j++)
            if((!(i&j)) and judge(i|j))
                A.a[i][j]=1;
}

inline Mat fast_pow(Mat a,int x){
    Mat ret=k;
    for(;x;x>>=1){
        if(x&1) ret=ret*a;
        a=a*a;
    }
    return ret;
}

int main(){
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    init();
    while(~scanf("%d%d",&n,&m),n){
        Mat B=k*fast_pow(A,n-1);
        LL ans=0;
        for(register int i=0;i<16;i++)
            if(judge(i)) ans+=B.a[0][i],ans%=m;
        printf("%lld
",ans);
    }
    return 0;
}

T3考场上推了半天,以为是个毒瘤dp,就开始狂码。结果爆零,最后说是国家集训队的作业题???全场拿分的就两个???最高的30???溜了。最后看了半天代码也没咋 懂,s数组表示的是差分数组,思想是把mod4意义下的数列变成普通的数列,只后似乎是一个贪心的思路,一直找最小值。代码先放这儿,以后再慢慢啃。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch))  {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
    return x*f;
}

using namespace std;
const int MAXN = 100005;

int n,a[MAXN],b[MAXN],c[MAXN],s[6];
int T,ans;

int main(){
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    T=rd();
    while(T--){
        n=rd();
        for(register int i=1;i<=n;i++) a[i]=rd();
        for(register int i=1;i<=n;i++) b[i]=rd(),c[i]=(4+b[i]-a[i])%4;
        ans=c[1];int j=0;
        memset(s,0,sizeof(s));
        for(register int i=2;i<=n;i++){
            s[(4+c[i]-c[i-1]-1)%4+1]++;
            if(c[i]<=c[i-1]) continue;
            for(j=0;!s[j];j++);
            s[j]--;
            ans+=j;
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdfzsyq/p/9676964.html