2017ccpc杭州现场赛
这场状态还行,过了8个题,不过罚时有点大,大概是少一题的去年我校4队的三倍。
A - Super-palindrome(hdu 6264)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6264
题解
签到题。显然这个串最后一定会变成ababab这样的形式,枚举奇数位和偶数位的字符,暴力算一下答案,取个最优就好了。
代码
#include<bits/stdc++.h>
#define N 105
using namespace std;
int T,n,sum,ans;char s[N];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf(" %s",s+1);n=strlen(s+1);ans=0;
for(int i=1;i<=n;i++)s[i]-='a';
for(int x=0;x<26;x++)
for(int y=0;y<26;y++)
{
sum=0;
for(int i=1;i<=n;i++)
{
if((i&1)&&s[i]==y)sum++;
if(!(i&1)&&s[i]==x)sum++;
}
ans=max(ans,sum);
}
for(int x=0;x<26;x++)
{
sum=0;
for(int i=1;i<=n;i++)if(s[i]==x)sum++;
ans=max(ans,sum);
}
printf("%d\n",n-ans);
}
return 0;
}
B - Master of Phi (hdu 6265)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6265
题解
对于每个质数的若干倍,它对答案的贡献是一样的。
所以2^20次爆搜每个质数选或不选,统计一下就好了。
这个题其实可以O(m)的做。
ans=nΣ(qi(1-1/pi)+1)
代码
队友写的,不贴代码了。
C - Hakase and Nano (hdu 6266)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6266
题解
先手的情况,只有场上所有石堆大小都是1且石堆数量为3的倍数才会输,不然先手必胜。
后手的情况,只要对手能一步搞到上面那种必败的情况你就必败,否则你必胜。
代码
#include<bits/stdc++.h>
using namespace std;
int T,n,d,x,cnt;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&d);cnt=0;
for(int i=1;i<=n;i++)scanf("%d",&x),cnt+=(x==1);
if(d==1)
{
if(cnt==n&&n%3==0)printf("No\n");
else printf("Yes\n");
}
else
{
if(n%3==1&&cnt>=n-1)printf("No\n");
else if(n%3==0&&cnt==n-1)printf("No\n");
else printf("Yes\n");
}
}
return 0;
}
D - Master of Random (hdu 6267)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6267
题解
每个点如果要有贡献,那么选择的子树的根必须是它到根的路径上的某个点。基于这个东西算下概率就好了。
代码
#include<bits/stdc++.h>
#define mod 998244353
#define ll long long
#define N 100005
using namespace std;
int T,n;ll num,sum,ans,s[N],f[N];
ll Pow(ll a,int b)
{
ll res=1;
while(b)
{
if(b&1)res=res*a%mod;
a=a*a%mod;b>>=1;
}
return res;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
sum=0;ans=0;num=Pow(n,mod-2);
for(int i=1;i<=n;i++)scanf("%lld",&s[i]);
for(int i=1;i<=n;i++)
{
f[i]=(sum*Pow(i-1,mod-2)%mod+1)%mod;
sum=(sum+f[i])%mod;
ans=(ans+s[i]*f[i]%mod*num)%mod;
}
printf("%lld\n",ans);
}
return 0;
}
E - Master of Subgraph (hdu 6268)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6268
题解
我们考虑枚举根,对于已知的根,求根必选的情况下,和根联通的联通快数值和的所有可能值。
考虑f[i]表示根节点必选,i的父亲必选,i不一定选的联通快的和的所以可能值的集合。
如果这个点选,那么就转移到它的dfs序下一位。
如果这个点不选,那么它的子树也不能选,就再dfs序上跳过它的子树转移到下一个点上。
即 (f[i]<<s[i])->f[i+1]
,f[i]->f[i+sdize[i]]
。
集合拿个bitset存一下就好了。
这样时间复杂度是 O(nn1e5/32) ,拿个点分治优化一下,少算一些重复状态,变成 O(nlogn1e5/32) 就能过了。
代码
#include<bits/stdc++.h>
#define inf 2100000000
#define N 3005
#define M 100010
using namespace std;
int T,n,m,s[N],check[N],flag[N],fa[N],size[N],w[N];
int k,la[N],ff[N*2],q[N],cnt,po[N],dfn[N];
struct node{int a,b;}e[N*2];
bitset<M>f[N],ans;
void add(int a,int b)
{
e[++k]=(node){a,b};ff[k]=la[a];la[a]=k;
e[++k]=(node){b,a};ff[k]=la[b];la[b]=k;
}
int find_root(int S)
{
int l=1,r=2,num=inf,res=0;q[1]=S;flag[S]=1;fa[S]=0;
while(l<r)
{
int x=q[l];l++;w[x]=0;size[x]=1;
for(int a=la[x];a;a=ff[a])
if(!flag[e[a].b]&&!check[e[a].b])
q[r]=e[a].b,flag[q[r]]=1,fa[q[r]]=x,r++;
}
for(int i=r-1;i;i--)
{
int x=q[i],val=max(w[x],r-size[x]-1);flag[x]=0;
if(fa[x])size[fa[x]]+=size[x],w[fa[x]]=max(w[fa[x]],size[x]);
if(val<num)num=val,res=x;
}
return res;
}
void dfs(int x)
{
po[dfn[x]=++cnt]=x;size[x]=1;
for(int a=la[x];a;a=ff[a])
if(!check[e[a].b]&&!dfn[e[a].b])
dfs(e[a].b),size[x]+=size[e[a].b];
}
void work()
{
f[po[1]][0]=1;
for(int i=1;i<=cnt;i++)
{
int x=po[i];ans|=(f[x]<<s[x]);
if(i+size[x]<=cnt)f[po[i+size[x]]]|=f[x];
f[po[i+1]]|=(f[x]<<s[x]);
}
for(int i=1;i<=cnt+5;i++)dfn[po[i]]=0,f[po[i]].reset();
}
void build(int x)
{
x=find_root(x);check[x]=1;cnt=0;dfs(x);work();
for(int a=la[x];a;a=ff[a])
if(!check[e[a].b])build(e[a].b);
}
int main()
{
int a,b;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);k=0;ans.reset();
memset(la,0,sizeof(la));
memset(ff,0,sizeof(ff));
memset(check,0,sizeof(check));
for(int i=1;i<n;i++)scanf("%d%d",&a,&b),add(a,b);
for(int i=1;i<=n;i++)scanf("%d",&s[i]);
build(1);
for(int i=1;i<=m;i++)printf("%d",(int)ans[i]);
printf("\n");
}
return 0;
}
G - Marriage (hdu 6270)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6270
题解
考虑容斥,我们需要求么n个家庭加起来至少有k对近亲的方案数。
每对家庭的方案数是C(a,k)*C(b,k)*k!
多个合并起来其实就是卷积,这个东西可以分治fft合并一下。
我们的做法是拿个堆每次取最小的两个多项式合并。
然后我们再根据至少k对近亲的方案数回推恰好k对近亲的方案数就好了。
代码
队友写的,不贴代码了。
J - Master of GCD(hdu 6273)
题目描述
http://acm.hdu.edu.cn/showproblem.php?pid=6273
题解
签到题。
前缀和维护下每个位置2的次幂和3的次幂,求个全局最小值算一下就好了。
队友傻逼错自闭了好久才过。。。
代码
队友写的,不贴代码了。