[20180826]四校联考

T1谜题(nazo)

Problem Here

Solution

  1. 先把所有点的开关状态压成一个二进制数
  2. 按一个按钮就相当于异或上一个二进制数
  3. 显然不会按同一个按钮两次
  4. 枚举\(\left\lfloor\frac{n}{2}\right\rfloor\)个按钮每个按不按,计算只按前\(\left\lfloor\frac{n}{2}\right\rfloor\)个按钮得到每种状态的最少次数保存在map里
  5. 接着枚举后$ \left\lceil \frac{n}{2} \right \rceil $个按钮每个按不按,根据按的按钮的异或和到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(n\log 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\n",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\n",ans);
	return 0;
}



T201串(kushi)

Problem Here

Solution

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

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

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

\(dp_{i,j}\to 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\n",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!

posted @ 2018-08-26 19:53  PaperCloud  阅读(318)  评论(0编辑  收藏  举报