• [20180826]四校联考


    T1谜题(nazo)

    Problem Here

    Solution

    1. 先把所有点的开关状态压成一个二进制数
    2. 按一个按钮就相当于异或上一个二进制数
    3. 显然不会按同一个按钮两次
    4. 枚举(leftlfloorfrac{n}{2} ight floor)个按钮每个按不按,计算只按前(leftlfloorfrac{n}{2} ight floor)个按钮得到每种状态的最少次数保存在map里
    5. 接着枚举后$ leftlceil frac{n}{2} ight ceil $个按钮每个按不按,根据按的按钮的异或和到map里找到对应状态并更新答案

    用hash表优化map,时间复杂度可优化到(O( 2^{frac{n}{2}}))



    #include<bits/stdc++.h>
    using namespace std;
    inline long long read(){
    	long long x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 45
    #define M 6233333
    int n,m,ans=40;
    long long t,res,opt[MN];
    struct Map{
    	struct edge{int nex,w;long long val;}e[M];int hr[M],cnt;
    	inline int&operator[](long long x){
    		register int i;
    		for(i=hr[x%M];i;i=e[i].nex)
    			if(e[i].val==x) return e[i].w;
    		e[++cnt]=(edge){hr[x%M],0,x};hr[x%M]=cnt;
    		return e[cnt].w;
    	}
    }mp;
    int main(){
    //	freopen("nazo.in","r",stdin);
    //	freopen("nazo.out","w",stdout);
    	n=read();m=read();
    	register int i,j,x,y,step;
    	for(i=0;i<n;i++) res^=((read()==0)*1ll)<<i,opt[i]|=1ll<<i;
    	for(i=1;i<=m;i++) x=read()-1,y=read()-1,opt[x]|=1ll<<y,opt[y]|=1ll<<x;
    	for(i=0;i<1<<n/2;i++){
    		for(t=res,j=step=0;j<n/2;j++) if((i>>j)&1) t^=opt[j],step++;
    		mp[t]=std::min(mp[t]?mp[t]:MN,step+1); 
    	}
    	for(i=0;i<1<<n-n/2;i++){
    		for(t=j=step=0;j<n-n/2;j++) if((i>>j)&1) t^=opt[n-j-1],step++;
    		mp[t]?ans=std::min(ans,mp[t]+step-1):0; 
    	}
    	return 0*printf("%d",ans);
    }
    



    T2染色(iro)

    Problem Here

    Solution

    假设最后用了(m)种颜色,我们把这些颜色编号为(1)~(m)

    (m)显然存在一个下界,即每两个相邻节点的颜色数之和的最大值。

    1. (n)为偶数时,答案就是这个最大值。如果您直接输出它,您会获得40分
    2. 当n为奇数时,假设1号点的颜色为(1)~(a_i),那么我要使偶数点所取得颜色尽可能小,奇数点所取得颜色尽可能大,显然可以通过贪心来完成。

    所以,二分答案加+贪心check,时间复杂度(O(nlog n))



    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 100005
    #define mid (l+r>>1)
    int n,a[MN],MIN;
    inline bool check(int md){
    	int x=a[2];
    	for(int i=3;i<=n;i++){
    		if(i&1){
    			x=std::max(0,a[i]-md+a[1]+x);
    		}
    		else{
    			x=std::max(0,a[i]-a[1]+x);
    		}
    		if(x==0) return 1;
    	}
    	return 0;
    }
    int main(){
    	n=read();
    	register int i;
    	for(i=1;i<=n;i++) a[i]=read(),MIN=std::max(MIN,a[i]+a[i-1]);
    	MIN=std::max(MIN,a[1]+a[n]);
    	if(~n&1) return 0*printf("%d
    ",MIN);
    	int l=MIN,r=MIN<<1,ans;
    	while(l<=r){
    		if(check(mid)) ans=mid,r=mid-1;
    		else l=mid+1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    



    T201串(kushi)

    Problem Here

    Solution

    首先有一个很好想得n方dp。——70分

    注意到我们只关心后缀,所以可以用后缀来表示状态

    (dp_{i,j})表示前i个01串,其中一个子序列的末尾存在一个后缀等于j的最小答案。

    (dp_{i,j} o dp_{i+1,j})有两种转移:

    1. 只要加上(g(a_i,a_{i+1})),可以直接加上这个值,若不执行该转移,将该值减去

    2. 枚举(a_{i+1})的一个前缀p,求出(min{dp_{i,p}}),再枚举(a_i)的后缀(u),用(min{dp_{i,p}})来更新(dp_{i+1,u})

    复杂度是(O(nm)).



    //70分dp
    #include<bits/stdc++.h>
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    inline int read01(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 1005
    int ans,n,m,a[MN];
    int cr[MN][MN],f[MN][MN];
    inline void rw(int &i,int j){
    	if(i<j) i=j; 
    }
    int main(){
    	freopen("kushi.in","r",stdin);
    	freopen("kushi.out","w",stdout);
    	n=read(),m=read();register int k,i,j;
    	if(n>1000) return 0*puts("orz");
    	for(i=1;i<=n;i++) a[i]=read01();
    	for(i=1;i<=n;i++)for(j=i+1;j<=n;j++)for(k=m;k>=0;k--)if((a[j]>>(m-k))==(a[i]%(1<<k))){cr[i][j]=k;break;}
    	for(i=0;i<=n;i++)for(j=0;j<=n;j++)if(i!=j){
    		if(i<j) rw(f[i][j+1],f[i][j]+cr[j][j+1]),
    				rw(f[j+1][j],f[i][j]+cr[i][j+1]);
    		else 	rw(f[i+1][j],f[i][j]+cr[i][i+1]),
    				rw(f[i][i+1],f[i][j]+cr[j][i+1]);
    	}
    	ans=0;
    	for(i=0;i<n;i++) rw(ans,f[i][n]),rw(ans,f[n][i]);
    	printf("%d
    ",m*n-ans);
    	return 0;
    }
    



    #include<bits/stdc++.h>
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    #define MN 200005
    #define inf (1e9)
    char s[25];
    int a[MN],f[25][1<<20],cr,res;
    int main(){
    //	freopen("kushi.in","r",stdin);
    //	freopen("kushi.out","w",stdout);
    	int n,m,i,j,k;
    	n=read();m=read();
    	for(i=1;i<=n;i++){
    		scanf("%s",s+1);
    		for(j=1;j<=m;j++) a[i]+=(s[j]=='0')<<j-1;
    	}
    	memset(f,67,sizeof f);
    	f[0][0]=m;
    	for(i=2;i<=n;i++){
    		for(k=0;k<m;k++)
    			if((a[i-1]>>k)==(a[i]&((1<<m-k)-1))) break;
    		cr+=k;res=inf;
    		for(j=0;j<=m;j++) res=std::min(res,f[m-j][a[i]&((1<<m-j)-1)]+j-k);
    		for(j=0;j<=m;j++) f[m-j][a[i-1]>>j]=std::min(f[m-j][a[i-1]>>j],res);
    	}
    	res=inf;
    	for(i=0;i<=m;i++)
    	for(j=0;j<1<<i;j++) res=std::min(res,f[i][j]);
    	printf("%d",res+cr);
    }
    





    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    【读书笔记】构建之法(CH4~CH6)
    【进度总结】第一个web应用程序(未完成)
    【读书笔记】构建之法(CH1~CH3)
    【进度总结】软件工程选题报告
    Intro Of Myself
    【读书笔记】人月神话
    .net知识系列之二:(net内置对象request,reponse,server,session,cookie,application,viewstate)
    .net知识系列之一:(XHTML语言,静态网页,动态网页,web服务器)
    Java—常量和变量
    Java入门
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/9538423.html
Copyright © 2020-2023  润新知