codeforces Avito Code Challenge 2018

C - Useful Decomposition

大致题意:一颗n个点的树,问能不能在树中找到若干个个简单路径,使得路径两两之间有且仅有一个公共点且没有公共边,能则输出任一方案。

画一画就能发现如果有两个点的度数大于1则不行

满足则以度数最多的点为所有路径起点dfs即可找到方案

#include<bits/stdc++.h>
#define rre(i,r,l) for(int i=(r);i>=(l);i--)
#define re(i,l,r) for(int i=(l);i<=(r);i++)
#define Clear(a,b) memset(a,b,sizeof(a))
#define inout(x) printf("%d",(x))
#define douin(x) scanf("%lf",&x)
#define strin(x) scanf("%s",(x))
#define op operator
typedef unsigned long long ULL;
typedef const int cint;
typedef long long LL;
using namespace std;
template<typename Q>
void inin(Q &x)
{
	x=0;int f=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	x=f?-x:x;
}
int n,head[100010],Next[200020],zhi[200020],ed,du[100010];
void add(int a,int b)
{
	Next[++ed]=head[a],head[a]=ed,zhi[ed]=b;
	Next[++ed]=head[b],head[b]=ed,zhi[ed]=a;
}
bool ans=1;
int da[100010],top;
void dfs(int x,int fa)
{
	int ss=0;
	for(int i=head[x];i;i=Next[i])if(zhi[i]!=fa)
		dfs(zhi[i],x),ss++;
	if(!ss)da[++top]=x;
	if(ss>1)ans=0;
}
int main()
{
	inin(n);
	re(i,2,n)
	{
		int aa,bb;
		inin(aa),inin(bb);
		add(aa,bb);du[aa]++,du[bb]++;
	}
	int Max=0,o,sum=0;
	re(i,1,n)if(du[i]>2)sum++;
	if(sum>1){cout<<"No";return 0;}
	re(i,1,n)if(du[i]>Max)Max=du[i],o=i;
	for(int i=head[o];i;i=Next[i])
		dfs(zhi[i],o);
	if(!ans)cout<<"No";
	else 
	{
		cout<<"Yes\n";
		cout<<top<<"\n";
		re(i,1,top)printf("%d %d\n",o,da[i]);
	}
	return 0;
}

D - Bookshelves

大致题意:给出含n个正整数序列和k,把序列分为k段,求每段的和 的 按位与 的和的最大值是多少

假设我们现在的任务是判断存不存在一个方案使答案\(x\)满足 \(x\)&\((1<<temp)==1\)

那么久用\(dp[i][j]\)表示把前i个数分为j段能否满足,转移则判断是否存在\(0<p<i\)\(dp[p][j-1]==1\)使得\((\sum_{q=p+1}^i q)\) & \((1<<temp)==(1<<temp)\)

按位temp从高到低判断即可,每次dp都在以前的高位dp基础上转移,复杂度\(O(n^4)\)

注意清空dp[i]!!!!

#include<bits/stdc++.h>
#define rre(i,r,l) for(int i=(r);i>=(l);i--)
#define re(i,l,r) for(int i=(l);i<=(r);i++)
#define Clear(a,b) memset(a,b,sizeof(a))
#define inout(x) printf("%d",(x))
#define douin(x) scanf("%lf",&x)
#define strin(x) scanf("%s",(x))
#define op operator
typedef unsigned long long ULL;
typedef const int cint;
typedef long long LL;
using namespace std;
template<typename Q>
void inin(Q &x)
{
	x=0;int f=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	x=f?-x:x;
}
int n,k;
LL a[55];
LL he(int l,int r)
{
	LL ret=a[l];
	re(i,l+1,r)ret+=a[i];
	return ret;
}
LL dp[55][55],ff[55][55],hh[55][55];
bool pd(LL x)
{
	re(i,0,n)re(j,0,k)dp[i][j]=ff[i][j];
	re(i,1,n)
	{
		Clear(dp[i],0);
		re(j,1,min(i,k))
		{
			re(p,j-1,i-1)
				if((hh[p+1][i]&x)==x&&dp[p][j-1])dp[i][j]=1;
		}
	}
	if(dp[n][k])re(i,0,n)re(j,0,k)ff[i][j]=dp[i][j];
	return dp[n][k];
}
void dfs(LL x,LL temp)
{
	if(x<0){cout<<temp;return ;}
	if(pd(temp|(1LL<<x)))temp|=(1LL<<x);
	dfs(x-1,temp);
}
int main()
{
	inin(n),inin(k);
	ff[0][0]=1;
	re(i,1,n)inin(a[i]);
	re(i,1,n)re(j,i,n)
		hh[i][j]=he(i,j);
	dfs(62,0);
	return 0;
}

E - Addition on Segments

大致题意:一个长度为n的初始全为0的序列,有q次区间加的操作\(l_i,r_i,x_i\),问是否存在这q次操作的子集使得执行这些操作后序列中的最大值为\(i\),从小到大输出满足\(1<=i<=n\)的所有\(i\)

考虑序列中的每个元素,如果执行的k次操作都覆盖这个点,则这个点一定是序列中的一个最大值,那么我们可以用这k个操作加的k个数来做背包大小为n的01背包,得出最大值为x的方案数。

把每个操作分为两个操作:加入\(x_i\),删除\(x_i\),从左到右计算每个元素的答案,加入一个数则在当前背包中反向循环一遍,删除则在当前背包中正向循环一遍。

划重点,01背包的删除操作

场上感觉方案数会爆炸,于是随机了一个模数来取模(就像一个hash),后来我试试不取模也过了,所以方案数不会很多?还是说随机数据没法卡?

#include<bits/stdc++.h>
#define rre(i,r,l) for(int i=(r);i>=(l);i--)
#define re(i,l,r) for(int i=(l);i<=(r);i++)
#define Clear(a,b) memset(a,b,sizeof(a))
#define inout(x) printf("%d",(x))
#define douin(x) scanf("%lf",&x)
#define strin(x) scanf("%s",(x))
#define op operator
typedef unsigned long long ULL;
typedef const int cint;
typedef long long LL;
using namespace std;
template<typename Q>
void inin(Q &x)
{
	x=0;int f=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	x=f?-x:x;
}
int n,q;
const int mod=1e9-rand()%2333;
struct wocao
{
	int wei,x,opt;
	bool op < (const wocao &rhs)const 
	{
		return wei<rhs.wei;
	}
}cz[20020];
int ed;
int ans[10010];
bool sum[10010];
void add(int x)
{
	rre(i,n,x)(ans[i]+=ans[i-x])%=mod;
}
void del(int x)
{
	re(i,x,n)ans[i]=(mod+ans[i]-ans[i-x])%mod;
}
int main()
{
	inin(n),inin(q);
	re(i,1,q)
	{
		int l,r,x;
		inin(l),inin(r),inin(x);
		ed++;
		cz[ed].wei=l,cz[ed].x=x,cz[ed].opt=1;
		ed++;
		cz[ed].wei=r+1,cz[ed].x=x,cz[ed].opt=-1;
	}
	sort(cz+1,cz+ed+1);
	ans[0]=1;int now=1;
	re(i,1,n)
	{
		while(cz[now].wei==i&&now<=ed)
		{
			if(cz[now].opt==1)add(cz[now].x);
			else del(cz[now].x);
			re(j,1,n)if(ans[j])sum[j]=1;
			now++;
		}
	}
	int ss=0;
	re(i,1,n)if(sum[i])ss++;
	cout<<ss<<"\n";
	re(i,1,n)if(sum[i])printf("%d ",i);
	return 0;
}

posted on 2018-05-28 15:45  No_CE_in_Vegetable  阅读(109)  评论(0编辑  收藏  举报

导航