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
";
cout<<top<<"
";
re(i,1,top)printf("%d %d
",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<<"
";
re(i,1,n)if(sum[i])printf("%d ",i);
return 0;
}