CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解

传送门


D. Destroy the Colony

首先明确题意:除了规定的两种(或一种)字母要在同侧以外,其他字母也必须在同侧。

发现当每种字母在左/右边确定之后,方案数就确定了,就是分组的方案数乘\(\frac{((n/2)!)^2}{\prod cnt_i!}\)。

分组的方案数考虑DP,设\(dp_{i,j}\)为前\(i\)个字母,占了左边\(j\)个位置的方案数,则有:

\[
dp_{i,j}=dp_{i-1,j-cnt_i}+dp_{i-1,j}
\]

当\(i\)是指定字母时特判即可。

这样复杂度为\(O(52^3n)\),无法通过。

考虑最多指定两次字母,而且字母顺序对结果没有关系,可以先把所有的DP出来,然后假装指定的两个字母是最后两个DP的,按照DP方程撤销即可。

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 101101
    #define mod 1000000007
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar();
        while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar();
        if(ch==‘.‘){ch=getchar();while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char __sr[1<<21],__z[20];int __C=-1,__Z=0;
    inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
    inline void print(register int x)
    {
        if(__C>1<<20)Ot();if(x<0)__sr[++__C]=‘-‘,x=-x;
        while(__z[++__Z]=x%10+48,x/=10);
        while(__sr[++__C]=__z[__Z],--__Z);__sr[++__C]=‘\n‘;
    }
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<‘\n‘;
        #endif
    }
    #ifdef mod
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
    ll inv(ll x){return ksm(x,mod-2);}
    #else
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
    #endif
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n,m,K;
char s[sz];
int a[sz],aa[sz];
int cnt[233];
ll T;

ll fac[sz],_fac[sz];
void init(){fac[0]=_fac[0]=1;rep(i,1,sz-1) fac[i]=fac[i-1]*i%mod,_fac[i]=inv(fac[i]);}
ll C(int n,int m){return n>=m&&m>=0?fac[n]*_fac[m]%mod*_fac[n-m]%mod:0;}

int sum[66];
ll dp[sz],cur[sz];
ll ans[66][66];
void Init()
{
    rep(i,1,K) sum[i]=sum[i-1]+cnt[i];
    dp[0]=1;
    int n=::n>>1;
    rep(i,1,K)
        drep(j,n,cnt[i])
            dp[j]=(dp[j]+dp[j-cnt[i]])%mod;
}
ll solve(int x,int y)
{
    int n=::n>>1;
    if ((cnt[x]>n&&x==y)||(cnt[x]+cnt[y]>n&&x!=y)) return 0;
    ll c=fac[n]*fac[n]%mod*inv(T)%mod;
    if (x==y) return c*dp[n]%mod;
    rep(i,0,n) cur[i]=dp[i];
    rep(j,cnt[x],n)
        cur[j]=(cur[j]-cur[j-cnt[x]]+mod)%mod;
    rep(j,cnt[y],n)
        cur[j]=(cur[j]-cur[j-cnt[y]]+mod)%mod;
    return c*cur[n-cnt[x]-cnt[y]]*2%mod;
}

int main()
{
    file();
    cin>>(s+1);n=strlen(s+1);
    rep(i,1,n) a[i]=aa[i]=s[i];
    sort(aa+1,aa+n+1);K=unique(aa+1,aa+n+1)-aa-1;
    rep(i,1,n) a[i]=lower_bound(aa+1,aa+K+1,a[i])-aa;
    rep(i,1,n) ++cnt[a[i]];
    init();Init();
    T=1;rep(i,1,K) T=T*fac[cnt[i]]%mod;
    rep(i,1,K) rep(j,1,K) ans[i][j]=solve(i,j);
    read(m);
    int x,y;
    while (m--) read(x,y),printf("%lld\n",ans[a[x]][a[y]]);
    return 0;
}

E. Tree

显然需要DP,但怎么DP呢?

考虑每个点只被自己的祖先限制,可以把要DP的点按某种方法排序,使得每个点的祖先都在自己之前处理完毕,就可以了。

设\(dp_{i,j}\)表示前\(i\)个点,分成\(j\)个集合的方案数,则有:

\[
dp_{i,j}=dp_{i-1,j}+(j-f_x)\times dp_{i-1,j}
\]

其中\(f_x\)表示\(x\)的祖先数。

这时又发现按\(f_x\)从小到大排序,就可以满足要求,于是就做完了。

注意出题人卡空间,DP需要滚掉一维。

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 101010
    #define mod 1000000007
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>‘9‘||ch<‘0‘) f|=(ch==‘-‘),ch=getchar();
        while(ch<=‘9‘&&ch>=‘0‘) t=t*10+ch-48,ch=getchar();
        if(ch==‘.‘){ch=getchar();while(ch<=‘9‘&&ch>=‘0‘) t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    inline void print(register int x)
    {
        if(C>1<<20)Ot();if(x<0)sr[++C]=‘-‘,x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]=‘\n‘;
    }
    void file()
    {
        #ifndef ONLINE_JUDGE
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<‘\n‘;
        #endif
    }
    #ifdef mod
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
    ll inv(ll x){return ksm(x,mod-2);}
    #else
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
    #endif
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n,Q;
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t)
{
    edge[++ecnt]=(hh){t,head[f]};
    head[f]=ecnt;
    edge[++ecnt]=(hh){f,head[t]};
    head[t]=ecnt;
}

int dfn[sz],son[sz],size[sz],dep[sz],top[sz],fa[sz],T;
#define v edge[i].t
void dfs1(int x,int fa)
{
    ::fa[x]=fa;dep[x]=dep[fa]+1;
    size[x]=1;
    go(x) if (v!=fa)
    {
        dfs1(v,x);
        size[x]+=size[v];
        if (size[v]>size[son[x]]) son[x]=v;
    }
}
void dfs2(int x,int fa,int tp)
{
    top[x]=tp;dfn[x]=++T;
    if (son[x]) dfs2(son[x],x,tp);
    go(x) if (v!=fa&&v!=son[x]) dfs2(v,x,v);
}
#undef v

int tr[sz];
void add(int x,int y){while (x<=n) tr[x]+=y,x+=(x&(-x));}
int query(int x){int ret=0;while (x) ret+=tr[x],x-=(x&(-x));return ret;}
int query(int x,int y){return query(y)-query(x-1);}

int Query(int x,int y)
{
    int ret=0;
    while (top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        ret+=query(dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y);
    ret+=query(dfn[x],dfn[y]);
    return ret;
}

int a[sz];
int f[sz];
inline bool cmp(const int &x,const int &y){return f[x]<f[y];}
ll dp[333];

int main()
{
    file();
    int x,y,K,m,rt;
    read(n,Q);
    rep(i,1,n-1) read(x,y),make_edge(x,y);
    dfs1(1,0);dfs2(1,0,1);
    while (Q--)
    {
        read(K,m,rt);
        rep(i,1,K) read(a[i]),add(dfn[a[i]],1);
        rep(j,1,m) dp[j]=0;
        dp[0]=1;
        rep(i,1,K) f[a[i]]=Query(rt,a[i])-1;
        sort(a+1,a+K+1,cmp);
        rep(i,1,K)
        {
            x=a[i];
            drep(j,m,f[x]+1) dp[j]=(dp[j-1]+dp[j]*(j-f[x])%mod)%mod;
            rep(j,0,f[x]) dp[j]=0;
        }
        ll ans=0;
        rep(i,1,m) (ans+=dp[i])%=mod;
        printf("%lld\n",ans);
        rep(i,1,K) add(dfn[a[i]],-1);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/p-b-p-b/p/10420602.html

时间: 2024-08-30 07:45:48

CodeCraft-19 and Codeforces Round #537 (Div. 2) 题解的相关文章

CodeCraft-19 and Codeforces Round #537 (Div. 2) - D. Destroy the Colony(动态规划+组合数学)

Problem  CodeCraft-19 and Codeforces Round #537 (Div. 2) - D. Destroy the Colony Time Limit: 2000 mSec Problem Description Input Output For each question output the number of arrangements possible modulo 10^9+7. Sample Input abba21 41 2 Sample Output

Codeforces Round #262 (Div. 2) 题解

A. Vasya and Socks time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasya has n pairs of socks. In the morning of each day Vasya has to put on a pair of socks before he goes to school. When

Codeforces Round #FF (Div. 2) 题解

比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n 

Codeforces Round #259 (Div. 2) 题解

A. Little Pony and Crystal Mine time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Twilight Sparkle once got a crystal from the Crystal Mine. A crystal of size n (n is odd; n?>?1) is an n?×?n 

Codeforces Round #177 (Div. 2) 题解

[前言]咦?现在怎么流行打CF了?于是当一帮大爷在执着的打div 1的时候,我偷偷的在刷div 2.至于怎么决定场次嘛,一般我报一个数字A,随便再拉一个人选一个数字B.然后开始做第A^B场.如果觉得机密性不高,来点取模吧.然后今天做的这场少有的AK了.(其实模拟赛只做完了4题,最后1题来不及打了) 等等,话说前面几题不用写题解了?算了,让我难得风光一下啦. [A] A. Polo the Penguin and Segments time limit per test 2 seconds mem

Codeforces Round #534 (Div. 2)题解

Codeforces Round #534 (Div. 2)题解 A. Splitting into digits 题目大意 将一个数字分成几部分,几部分求和既是原数,问如何分可以使得分出来的各个数之间的差值尽可能小 解题思路 将n分成n个1相加即可 AC代码 #include<cstring> #include<string> #include<iostream> #include<cstdio> using namespace std; int main

Codeforces Round #561 (Div. 2) 题解

Codeforces Round #561 (Div. 2) 题解 题目链接 A. Silent Classroom 水题. Code #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 105; int n; char s[N], t[N]; int main() { cin >> n; for(int i = 1; i <= n; i++) { scanf(&q

Codeforces Round #608 (Div. 2) 题解

目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 程序 D. Portals 题意 做法 程序 E. Common Number 题意 做法 程序 结束语 Codeforces Round #608 (Div. 2) 题解 前言 题目链接:仅仅只是为了方便以题目作为关键字能查找到我的题解而已(逃 Codeforces 1271A Codeforce

Codeforces Round #617 (Div. 3) 题解

目录 Codeforces Round #617 (Div. 3) 题解 前言 A. Array with Odd Sum 题意 做法 程序 B. Food Buying 题意 做法 程序 C. Yet Another Walking Robot 题意 做法 程序 D. Fight with Monsters 题意 做法 程序 E1. String Coloring (easy version) 题意 做法 程序 E2. String Coloring (hard version) 题意 做法