【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);
    }
}
posted @ 2019-02-21 21:07  Newuser233  阅读(6)  评论(0)    收藏  举报