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

    7.5 模拟赛

    DP专题

    A 涂色paint

    明显的区间DP

    转移方程:

    [f[i][j]=egin{cases} max(f[i+1][j],f[i][j-1]);(c[i]==c[j])\ max(f[i][k]+f[k+1][j]);(c[i]!=c[j]) end{cases} ]

    码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<map>
    #include<queue>
    #include<deque>
    #include<set>
    #include<stack>
    #include<bitset>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int INF=0x3f3f3f3f,N=100010;
    
    inline int read(){
        int x=0,y=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
        while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
        return x*y;
    }
    
    int n,w[N],s[N];
    int t,h,q[N];
    int f[N],g[N];
    
    int main(){
    
        n=read();
        for(int i=n;i>=1;i--) w[i]=read();
        for(int i=1;i<=n;i++) s[i]=s[i-1]+w[i];
    
        h=0,t=0;
        for(int i=1;i<=n;i++){
            while(h<t&&s[q[h+1]]+g[q[h+1]]<=s[i]) ++h;
            f[i]=f[q[h]]+1;
            g[i]=s[i]-s[q[h]];
            while(h<t&&s[q[t]]+g[q[t]]>=s[i]+g[i]) --t;
            q[++t]=i;
        }
    
        printf("%d
    ",f[n]);
        
        return 0;
    }
    

    B 粉刷匠

    预处理+分组背包

    预处理出每个木板涂k次最多能涂对多少块,线性DP

    用分组背包,每个木板为一组,每个木板涂多少次是1个单位

    选就完了

    码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<map>
    #include<queue>
    #include<deque>
    #include<set>
    #include<stack>
    #include<bitset>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int INF=0x3f3f3f3f;
    
    int n,m,t,mapp[55][2510];
    int g[55][2510][55],f[2][2510];
    
    inline int read(){
        int x=0,y=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
        while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
        return x*y;
    }
    
    int main(){
    
        n=read(),m=read(),t=read();
        for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
            mapp[i][0]=0;
            char a;cin>>a;
            mapp[i][j]=mapp[i][j-1]+(a=='1');
        }
    
        for(int i=1;i<=n;i++)
    	    for(int j=1;j<=m;j++)
    	        for(int k=1;k<=m;k++)
    	            for(int q=j-1;q<k;q++)
    		            g[i][j][k]=max(g[i][j][k],g[i][j-1][q]+max(mapp[i][k]-mapp[i][q],k-q-mapp[i][k]+mapp[i][q]));//涂0还是涂1
    
        for(int i=1;i<=n;i++){
            for(int j=1;j<=t;j++){
                for(int k=0;k<=min(m,j);k++){
                    int op=(i%2)^1;
                    f[i&1][j]=max(f[i&1][j],f[op][j-k]+g[i][k][m]);
                }
            }
        }
    
        int ans=0;
    
        for(int i=1;i<=t;i++) ans=max(ans,f[n&1][i]);
    
        printf("%d
    ",ans);
        
        return 0;
    }
    

    C 花神的数论题

    数位DP板子无压力

    甚至不用记录前导零和原数

    码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<map>
    #include<queue>
    #include<deque>
    #include<set>
    #include<stack>
    #include<bitset>
    #include<cstring>
    #define ll long long
    using namespace std;
    const ll INF=0x3f3f3f3f,Mod=10000007;
    
    ll n,len,ans=1,a[55];
    ll f[55][55];
    
    inline ll read(){
        ll x=0,y=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
        while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
        return x*y;
    }
    
    ll dfs(int pos,int sum1,int lim){
        if(pos>len){
            if(sum1!=0) return sum1%Mod;
            return 1;
        }
        if(!lim&&f[pos][sum1]!=-1) return f[pos][sum1]%Mod;
        ll res=1;
        int ret=lim?a[len-pos+1]:1;
        for(int i=0;i<=ret;i++){
            (res*=dfs(pos+1,sum1+(i==1),(lim&&i==ret)))%=Mod;
        }
        if(!lim) f[pos][sum1]=res;
        return res;
    }
    
    ll part(ll x){
        len=0;
        while(x){a[++len]=x&1,x>>=1;}
        memset(f,-1,sizeof f);
        ll res=dfs(1,0,1);
        return res;
    }
    
    int main(){
    
        n=read();
        printf("%lld
    ",part(n));
    
        
        return 0;
    }
    

    D 合法序列

    注意到该题的k很小,最大也只能到4,所以我们可以枚举这k位,而这k位对整个序列合法性判断上的影响也只有16位,也可以直接枚举,最大枚举量为(2^{2^4}),即131072

    我们每枚举到一个(2^{2^k})的状态,就判断它是不是合法的,如果它不合法,那么就舍去这种情况,如果合法,就继续转移

    转移方程方面,我们设f[i][S]为从第i位开始k位是状态S,我们在枚举出来的(2^{2^k})的状态必然合法,那么我们把最后一个长度为k的串在f数组中标记为1

    接下来就把这个枚举的序列不断向后移去转移

    转移有点难

    我们需要先把枚举的状态转移成上一个状态,即取该状态的后k-1位,然后左移一位,就是上一个状态,最后一位取1时函数值与最后一位取0时函数值之和就是该状态的函数值

    用到了a或上b再异或上b就是把b是1的位在a中都设成0

    码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<string>
    #include<cmath>
    #include<vector>
    #include<map>
    #include<queue>
    #include<deque>
    #include<set>
    #include<stack>
    #include<bitset>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int INF=0x3f3f3f3f,N=510,Mod=998244353;
    
    int n,k,res=0;
    int g[N],f[N][N];
    
    inline int read(){
        int x=0,y=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
        while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
        return x*y;
    }
    
    int main(){
    
    	n=read(),k=read();
    
    	for(int i=0;i<(1<<k);i++){
    		for(int j=0;j<k;j++){
                g[i]|=((i>>j)&1)*(1<<(k-j-1));
            }
    	}//编号和状态位置相反
    
    	for(int i=0;i<(1<<(1<<k));i++){
    		int flg=1;
    		for(int j=0;j<=(1<<k)-k;j++){
    			int op=((1<<k)-1)&(i>>j);//取该状态的每个k位
    			op=g[op];
    			if(i&(1<<op)) continue;//合法吗
    			flg=0;
    			break;
    		}
    
    		if(!flg)continue;
    		memset(f,0,sizeof(f));
    
    		f[(1<<k)-1][i>>((1<<k)-k)]=1;
    
    		for(int j=(1<<k);j<n;j++){//从16开始往后dp
                for(int l=0;l<(1<<k);l++){//枚举状态
                    if((i&(1<<g[l]))==0) continue;
                    
                    int op=((l|(1<<(k-1)))^(1<<(k-1)))<<1;
    			//cout<<j<<" "<<l<<" "<<op<<endl;
    
                    f[j][l]=(f[j-1][op|1]+f[j-1][op])%Mod;
                }
    		}
    
    		for(int j=0;j<(1<<k);j++) res=(res+f[n-1][j])%Mod;
    
    	}
    	
        printf("%d
    ",res);
        
        
        return 0;
    }
    
    
  • 相关阅读:
    DS博客作业06--图
    DS博客作业05--树
    DS博客作业04--树大作业说明
    DS博客作业02--栈和队列
    DS博客作业01--线性表
    DS博客作业01--日期抽象数据类型设计与实现
    C语言博客作业06--结构体&文件
    DEVC怎么建工程
    C语言博客05--指针
    201771010110孔维滢《面向对象程序设计(java)》第十二周学习总结
  • 原文地址:https://www.cnblogs.com/wsyunine/p/14974050.html
Copyright © 2011-2022 走看看