zoukankan      html  css  js  c++  java
  • NOIP2006提高组题解

    (D1T1) 能量项链 ((OK))

    (D1T2) 金明的预算方案 ((OK))

    (D1T3) 作业调度方案 ((OK))

    (D1T4) (2^k)进制数 ((OK?))

    姑且算是完结撒花,(T4)有高精的部分就懒得写了.

    (T1) 仅次于石子合并的区间(DP)模板题(???).设(f[i][j])表示合并区间([i,j])的最大得分,则枚举区间断点(k),(f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]*head[i]*tail[k](head[k+1])*tail[j])).

    然后项链是个环,倍长数组从而断环为链是常规操作吧.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=205;
    int head[N],tail[N],f[N][N];
    int main(){
    	int n=read();
    	for(int i=1;i<=n;++i){
    		head[i]=read();
    		tail[i-1]=head[i];
    	}tail[n]=head[1];
    	for(int i=1;i<=n;++i)head[i+n]=head[i],tail[i+n]=tail[i];
    	for(int len=2;len<=n;++len){
    		for(int i=1;i+len-1<=n*2;++i){
    			int j=i+len-1;
    			for(int k=i;k<j;++k)
    				f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+head[i]*tail[k]*tail[j]);		
    		}
    	}
    	int ans=0;for(int i=1;i<=n;++i)ans=max(ans,f[i][i+n-1]);
    	printf("%d
    ",ans);
        return 0;
    }
    
    

    (T2) 有依赖性的(有主附件的)(01)背包模板题.设(f[i][j])表示考虑到了第(i)件主件物品,占用背包体积为(j)时的最大价值.转移的时候模型还是(01)背包的模型(因为不论是主件还是附件,都只有选或者不选两种情况),暴力枚举出所有的四种情况(只选主件,选主件和附件一,选主件和附件二,选主件和两个附件)即可.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=105;
    int tot,ans,sum[N],f[N][32005];
    struct node{int v,w,id;}e[N],g[N][3];
    int main(){
    	int m=read(),n=read();
    	for(int i=1;i<=n;++i){
    		int a=read(),b=read(),c=read();
    		if(!c){
    			e[++tot].v=a;e[tot].w=b;e[i].id=tot;
    		}
    		if(c){
    			c=e[c].id;
    			g[c][++sum[c]].v=a;g[c][sum[c]].w=b;
    		}
    	}
    	for(int i=1;i<=tot;++i){
    		for(int j=m;j>=0;--j){
    			f[i][j]=f[i-1][j];
    			if(j>=e[i].v)f[i][j]=max(f[i][j],f[i-1][j-e[i].v]+e[i].v*e[i].w);
    			if(j>=e[i].v+g[i][1].v)f[i][j]=max(f[i][j],f[i-1][j-e[i].v-g[i][1].v]+e[i].v*e[i].w+g[i][1].v*g[i][1].w);
    			if(j>=e[i].v+g[i][2].v)f[i][j]=max(f[i][j],f[i-1][j-e[i].v-g[i][2].v]+e[i].v*e[i].w+g[i][2].v*g[i][2].w);
    			if(j>=e[i].v+g[i][1].v+g[i][2].v)f[i][j]=max(f[i][j],f[i-1][j-e[i].v-g[i][1].v-g[i][2].v]+e[i].v*e[i].w+g[i][1].v*g[i][1].w+g[i][2].v*g[i][2].w);
    		}
    	}
    	printf("%d
    ",f[tot][m]);
        return 0;
    }
    
    

    (T3)根据题意来模拟即可.一边写代码的时候就一边做了注释,这里懒得讲了.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=21;
    const int M=405;
    int ord[M],bel[N][N],tim[N][N],Has[N],End[N],maxn[N],bj[N][100005];
    int main(){
    	int m=read(),n=read();
    	for(int i=1;i<=n*m;++i)ord[i]=read();//第i个顺序安排哪个工件
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)bel[i][j]=read();//第i个工件的第j道工序在哪个机器上完成
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)tim[i][j]=read();//第i个工件的第j道工序所需时间
    	int ans=0;
    	for(int i=1;i<=n*m;++i){
    		int now=ord[i];//当前安排哪个工件
    		int has=++Has[now];//该工件当前到第几个工序了
    		int jqh=bel[now][has];//要在哪个机器上完成
    		int sum=0,BJ=0;
    		for(int j=max(0,End[now])+1;j<=maxn[jqh];++j){//能插之前的空就插之前的空
    			if(!bj[jqh][j])++sum;
    			else sum=0;
    			if(sum>=tim[now][has]){
    				for(int k=j;k>=j+1-tim[now][has];--k)bj[jqh][k]=1;
    				End[now]=j;BJ=1;break;
    			}
    		}
    		if(!BJ){//否则就要在这个机器后面新开一段时间
    			int st=max(maxn[jqh],End[now]);
    			for(int j=st+1;j<=st+tim[now][has];++j)bj[jqh][j]=1;
    			maxn[jqh]=st+tim[now][has];End[now]=maxn[jqh];ans=max(ans,maxn[jqh]);
    		}
    	}
    	printf("%d
    ",ans);
        return 0;
    }
    
    

    (T4)(f[i][j])表示从右往左第(i)位填数字(j)时的方案数,则(f[i][j]=sum_{x=j+1}^{2^k-1}f[i-1][x]),如果每次转移的时候暴力枚举([j+1,2^k-1])显然会超时,所以要前缀和优化,即每次更新(f[i-1][j])的同时维护一下(sum[i-1][j]=sum[i-1][j-1]+f[i-1][j]),那么转移(f[i][j])的时候直接(O(1))(f[i][j]=sum[i-1][2^k-1]-sum[i-1][j])即可.

    反正我交上去获得了(50)分,我就默认剩下(50)分都是高精了啊.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=15005;
    int k,w,bj;
    int Base[10];
    ll f[N][520],sum[N][520];
    int main(){
    	Base[0]=1;for(int i=1;i<=9;++i)Base[i]=Base[i-1]<<1;
    	k=read();w=read();int n=w/k;if(w%k)bj=1,++n;
    	for(int j=0;j<=Base[k]-1;++j)f[1][j]=1,sum[1][j]=sum[1][j-1]+f[1][j];
    	for(int i=2;i<=n;++i){
    		for(int j=1;j<=Base[k]-1;++j){
    			f[i][j]=sum[i-1][Base[k]-1]-sum[i-1][j];
    			sum[i][j]=sum[i][j-1]+f[i][j];
    		}
    	}
    	if(bj){
    		ll ans=0;
    		for(int i=2;i<n;++i)
    			for(int j=1;j<=Base[k]-1;++j)ans+=f[i][j];
    		for(int j=1;j<=Base[(Base[k]%w)-1];++j)ans+=f[n][j];
    		printf("%lld
    ",ans);return 0;
    	}
    	ll ans=0;
    	for(int i=2;i<=n;++i)
    		for(int j=1;j<=Base[k]-1;++j)ans+=f[i][j];
    	printf("%lld
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
    dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
    dotnet 控制台 Hangfire 后台定时任务
    dotnet 控制台 Hangfire 后台定时任务
    dotnet 获取指定进程的输入命令行
    dotnet 获取指定进程的输入命令行
    PHP sqrt() 函数
    PHP sinh() 函数
    PHP sin() 函数
    PHP round() 函数
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11815710.html
Copyright © 2011-2022 走看看