【CF】CodeCraft-19 and Codeforces Round #537 (Div. 2)
cf补题计划
A 水题模拟
#include<iostream>
#include<cstdio>
using namespace std;
string s,t;
int n,m;
bool BJ[200];
int main() {
cin>>s>>t;
n = s.length(); m = t.length();
BJ['a'] = BJ['e'] = BJ['i'] = BJ['o'] = BJ['u'] = 1;
if(n!=m) puts("no");
else {
for(int i=0;i<n;i++) {
if(BJ[s[i]]!=BJ[t[i]]) {
puts("no"); return 0;
}
}
puts("yes");
}
}
B 有n个人,每个人都有权值,然后你有m次操作,每次操作可以删掉一个人或者给一个人的权值加一,使得最后剩下的人平均数最大。
枚举删几个人,最后取最大就可以了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define int long long
using namespace std;
const int maxn = 1e5+5;
typedef double db;
int a[maxn],n,k,m;
main() {
scanf("%I64d%I64d%I64d",&n,&k,&m);
for(int i=1;i<=n;i++) {
scanf("%I64d",&a[i]);
}
sort(a+1,a+1+n);
for(int i=n;i>=0;i--) a[i] += a[i+1];
db ans = 0;
for(int i=0;i<=min(n,m);i++) {
int o = n-i; if(o==0) break;
db sm = a[i+1] + min(m-i,o*k);
ans = max(ans,sm/o);
}
printf("%.10f",ans);
}
C 题意:有2^n个格子,格子可能是空的,也可能站着许多人,有两种操作。操作一是把某一列格子平均分成两部分,操作二是把某一列格子摧毁,如果这一列格子上没有人,那么就需要耗费A的代价,如果格子上有na个人,那么就要耗费Bnal 的代价,问把所有格子全部摧毁的最小代价是啥。
暴力递归看一下,,就可以了,没有太多难度
\#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define int long long
using namespace std;
const int maxn = 3e5+5;
int n,k,A,B;
int sm[maxn*20],rt,ls[maxn*20],rs[maxn*20],tot;
void ins(int &p,int l,int r,int x) {
if(!p) p = ++tot;
sm[p]++;
if(l==r) return;
int mid = (l+r)>>1;
if(x<=mid)ins(ls[p],l,mid,x);
else ins(rs[p],mid+1,r,x);
}
int gsum(int &p,int l,int r,int x,int y) {
if(p==0) return 0;
if(x<=l&&r<=y) return sm[p];
int mid = (l+r)>>1;
if(y<=mid) return gsum(ls[p],l,mid,x,y);
else if(x>mid) return gsum(rs[p],mid+1,r,x,y);
else return gsum(ls[p],l,mid,x,y) + gsum(rs[p],mid+1,r,x,y);
}
int S;
int DJ(int l,int r) {
int o = gsum(rt,1,S,l,r);
if(o==0) return A;
else {
if(l<r)return min(B*(r-l+1)*o,DJ(l,(l+r)>>1)+DJ( ((l+r)>>1)+1,r));
else return B*o;
}
}
main() {
scanf("%I64d%I64d%I64d%I64d",&n,&k,&A,&B);
S = (1<<n);
for(int i=1;i<=k;i++) {
int x; scanf("%I64d",&x);
ins(rt,1,S,x);
}
printf("%I64d",DJ(1,S));
}
D 补
钢铁侠必须要选择类型和x,y两洞穴中类型相同的反派,把它们移动到殖民地的前半部或者后半部,并且剩余的反派,如果是同一类型,也要呆在同一边。问这样移动的方案数。(真是毒瘤的题面)
由于一共只有52种字母,那么询问的类别也最多只有2500种左右。
接下来考虑其实就是把若干个字母种集合划分到两个n/2的集合中,然后,保证两个集合的字母个数分别都是n/2,那么我们就得到了((n/2)!)^2 / (\sum cnt!) (cnt表示每种字母的个数)个方案。那么我们现在需要解决的就是集合划分,并且集合的划分询问的x种字母必须和y种字母在一起。
不考虑x和y的集合划分方案其实就是问组成n/2的物品的方案数,背包之。求出来之后对每个x和y在背包中减去他们的贡献就可以了(退背包)。
这道题还是很有趣的DP
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int mod = 1e9+7;
int add(int x,int y) { x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y) { x-=y; return x<0?x+mod:x; }
int mul(int x,int y) { return 1ll*x*y%mod; }
int ksm(int a,int b) {
int ans = 1;
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans = mul(ans,a);
return ans;
}
char ss[100005];
int n,q;
int cnt[55];
int qr[55][55];
int dp[50005],f[50005];
int gid(char o) {
if(o>='a'&&o<='z') return o-'a'+1;
else return o-'A'+27;
}
int fac[100005],inv[100005];
int main() {
scanf("%s",&ss[1]);
n = strlen(ss+1);
fac[0] = 1;
for(int i=1;i<=n;i++) cnt[gid(ss[i])]++,fac[i]=mul(fac[i-1],i);
inv[n] = ksm(fac[n],mod-2);
for(int i=n-1;i>=0;i--) inv[i] = mul(inv[i+1],i+1);
int ORZ = mul(fac[n/2],fac[n/2]);
for(int i=1;i<=52;i++) ORZ = mul(ORZ,inv[cnt[i]]);
scanf("%d",&q);
dp[0] = 1;
for(int i=1;i<=52;i++) {
if(!cnt[i]) continue;
for(int j=n/2;j>=cnt[i];j--) {
dp[j] = add(dp[j],dp[j-cnt[i]]);
}
}
for(int tx=1;tx<=52;tx++) {
if(!cnt[tx]) continue;
for(int ty=tx;ty<=52;ty++) {
if(!cnt[ty]) continue;
for(int j=0;j<=n/2;j++) f[j] = dp[j];
for(int j=cnt[tx];j<=n/2;j++) f[j]=sub(f[j],f[j-cnt[tx]]);
if(tx!=ty)for(int j=cnt[ty];j<=n/2;j++) f[j]=sub(f[j],f[j-cnt[ty]]);
qr[tx][ty] = qr[ty][tx] = mul(f[n/2],2);
}
}
for(int i=1;i<=q;i++) {
int x,y; scanf("%d%d",&x,&y);
printf("%d\n",mul(ORZ,qr[gid(ss[x])][gid(ss[y])]));
}
}
E 补
给出一棵树,q次询问,每次询问给出k个树上的点,然后给出r,以r这个节点为根,将这k个点分成m组,要求组内的点,任意两点不能有祖先关系。求方案分配数。
我们考虑如果1为根的话,f[i][j]表示前i个点,第i个点放入第j个集合中的方案数,然后
如果g[i]表示i到根路径有多少个祖先的话
f[i][j] = f[i-1][j]* (j-g[i]) + f[i-1][j-1]
如果换根为r,就是统计x到r路径上有多少个点了。DFS+树状数组+树剖求LCA实现之.
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define lowbit(x) ((x)&(-x))
using namespace std;
const int mod = 1e9+7;
const int maxn = 2e5+5;
int add(int x,int y) { x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y) { x-=y; return x<0?x+mod:x; }
int mul(int x,int y) { return 1ll*x*y%mod; }
int ksm(int a,int b) {
int ans;
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans = mul(ans,a);
return ans;
}
int en[maxn],nt[maxn],la[maxn],owo;
void adg(int x,int y) { en[++owo]=y; nt[owo]=la[x]; la[x]=owo; }
int bit[maxn];
int n,q;
void abit(int x,int d) {
for(;x<=n;x+=lowbit(x)) bit[x]+=d;
}
int gsum(int x) {
int sm = 0; for(;x;x-=lowbit(x)) sm+=bit[x]; return sm;
}
int IN[maxn],OUT[maxn],dfx,sz[maxn],zerz[maxn];
void dfs(int x,int ba) {
sz[x] = 1;
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(y==ba) continue;
dfs(y,x);
sz[x] += sz[y];
if(sz[y]>sz[zerz[x]]) zerz[x] = y;
}
}
int top[maxn],dep[maxn],fa[maxn];
void dds(int x,int ba,int ace) {
IN[x] = ++dfx; fa[x] = ba;
dep[x] = dep[ba] + 1;
top[x] = ace;
if(zerz[x]) dds(zerz[x],x,ace);
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(y==ba||y==zerz[x]) continue;
dds(y,x,y);
}
OUT[x] = dfx;
}
int K,M,R;
bool mark[maxn];int p[maxn],dp[maxn],ff[maxn],ps[maxn];
bool cmp(int x,int y) {
return ff[x]<ff[y];
}
int glca(int x,int y) {
while(top[x]!=top[y]) {
dep[top[x]]<dep[top[y]]?y=fa[top[y]]:x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int main() {
scanf("%d%d",&n,&q);
for(int i=1;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
adg(x,y); adg(y,x);
}
dfs(1,0);
dds(1,1,1);
while(q--) {
scanf("%d%d%d",&K,&M,&R);
for(int i=1;i<=K;i++) {
scanf("%d",&p[i]);
abit(IN[p[i]],1); abit(OUT[p[i]]+1,-1);
mark[p[i]] = 1;
}
int ansr = gsum(IN[R]);
dp[0] = 1; for(int j=1;j<=M;j++) dp[j] = 0;
for(int i=1;i<=K;i++) {
int lcc = glca(p[i],R);
ff[i] = gsum(IN[p[i]]) + ansr - 1 - 2*gsum(IN[lcc]) + mark[lcc];
}
for(int i=1;i<=K;i++) {
abit(IN[p[i]],-1); abit(OUT[p[i]]+1,1);
mark[p[i]] = 0;
}
for(int i=1;i<=K;i++) ps[i] = i;
sort(ps+1,ps+1+K,cmp);
cerr<<ff[ps[K]]<<endl;
if(ff[ps[K]]>=M) { puts("0"); continue; }
for(int i=1;i<=K;i++) {
int o = ps[i];
for(int j=min(i,M);j>=0;j--) {
if(ff[o]>=j) dp[j] = 0;
else dp[j] = add(mul(dp[j],sub(j,ff[o])),dp[j-1]);
}
}
int ans = 0;
for(int i=1;i<=M;i++) ans = add(ans,dp[i]);
printf("%d\n",ans);
}
}