《P4099 [HEOI2013] SAO》

题目描述

Welcome to SAO ( Strange and Abnormal Online)。这是一个 VR MMORPG, 含有 n 个关卡。但是,挑战不同关卡的顺序是一个很大的问题。

某款游戏有 n−1 个对于挑战关卡的限制,诸如第 i 个关卡必须在第 j 个关卡前挑战,或者完成了第 k 个关卡才能挑战第 l 个关卡。并且,如果不考虑限制的方向性,那么在这 n−1 个限制的情况下,任何两个关卡都存在某种程度的关联性。即,我们不能把所有关卡分成两个非空且不相交的子集,使得这两个子集之间没有任何限制。

输入格式

第一行,一个整数 T,表示数据组数。

对于每组数据,第一行一个整数 n,表示关卡数。接下来 n−1 行,每行为 i sign j,其中 0≤i,j≤n−1 且 i=j,sign 为 < 或者 >,表示第 i 个关卡必须在第 j 个关卡前或后完成。

输出格式

对于每个数据,输出一行一个整数,为攻克关卡的顺序方案个数,mod(109+7) 输出。

输入输出样例

输入 #1复制

复制代码
2 
5 
0 < 2 
1 < 2 
2 < 3 
2 < 4 
4 
0 < 1 
0 < 2 
0 < 3

输出 #1复制

复制代码
4 
6

说明/提示

对于 20% 的数据有 n≤10。

对于 40% 的数据有 n≤100。

对于另外 20% 的数据有,保证数据中 sign 只会是 <,并且 i<j。

对于 100% 的数据有 T≤5,1≤n≤1000。

代码实现:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

inline ll rd() {
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return x*f;
}

ll pow(ll x,ll y,ll p) {
    ll ans=1;
    for(;y;y>>=1,x=x*x%p)
        if(y&1) ans=ans*x%p;
    return ans;
}

ll gcd(ll x,ll y) {
    if(y==0) return x;
    return gcd(y,x%y);
}

ull cnt,MOD,g[1010][1010],T,f[1010][1010],C[2010][2010],e[1010][1010],sz[101000];
ll a[101000],b[101000],c[101000],d[101000],ans,n,i,x,y;
string s;

void add(int x,int y,int z) {
    cnt++;a[cnt]=y;b[cnt]=d[x];c[cnt]=z;d[x]=cnt;
}

void dfs(int x,int fa) {
    int i,p1,p2,p3;
    sz[x]=1;f[x][1]=1;
    for(i=d[x];i;i=b[i]) {
        if(a[i]==fa) continue;
        dfs(a[i],x);
        if(c[i]==1) {
            for(p1=1;p1<=sz[x]+sz[a[i]];p1++) e[x][p1]=0;
            g[a[i]][sz[a[i]]]=f[a[i]][sz[a[i]]];g[a[i]][sz[a[i]]+1]=0;
            for(p1=sz[a[i]]-1;p1>=1;p1--) g[a[i]][p1]=(g[a[i]][p1+1]+f[a[i]][p1])%MOD;
            for(p1=sz[x];p1>=1;p1--)
                for(p3=0;p3<=sz[a[i]]-1;p3++)
                    e[x][p1+p3]=(e[x][p1+p3]+f[x][p1]*g[a[i]][p3+1]%MOD*C[p1+p3-1][p3]%MOD*C[sz[x]-p1+sz[a[i]]-p3][sz[a[i]]-p3]%MOD)%MOD;
        } else {
            for(p1=1;p1<=sz[x]+sz[a[i]];p1++) e[x][p1]=0;
            for(p1=1;p1<=sz[a[i]];p1++) g[a[i]][p1]=(g[a[i]][p1-1]+f[a[i]][p1])%MOD;
            for(p1=sz[x];p1>=1;p1--)
                for(p3=1;p3<=sz[a[i]];p3++)
                    e[x][p1+p3]=(e[x][p1+p3]+f[x][p1]*g[a[i]][p3]%MOD*C[p1+p3-1][p3]%MOD*C[sz[x]-p1+sz[a[i]]-p3][sz[a[i]]-p3]%MOD)%MOD;
        }
        for(p1=1;p1<=sz[x]+sz[a[i]];p1++) f[x][p1]=e[x][p1];
        sz[x]+=sz[a[i]];
    }
}

int main() {
    ios::sync_with_stdio(0);cin.tie();cout.tie();
    cin>>T;MOD=1e9+7;
    C[0][0]=1;
    for(i=1;i<=2000;i++) {
        C[i][0]=1;C[i][i]=1;
        for(ull j=1;j<i;j++)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
    }
    for(;T;T--) {
        cin>>n;cnt=0;
        for(i=1;i<=n;i++) d[i]=0,sz[i]=0;
        for(i=1;i<n;i++) {
            cin>>x>>s>>y;
            x++;y++;
            if(s=="<") add(x,y,1),add(y,x,2);
            else add(x,y,2),add(y,x,1);
        }
        for(i=1;i<=n;i++)
            for(ull j=1;j<=n;j++)
                f[i][j]=0;
        dfs(1,0);
        ans=0;
        for(i=1;i<=n;i++) ans=(ans+f[1][i])%MOD;
        printf("%llu\n",ans);
    }
    return 0;
}
相关推荐
Jasmine_llq1 天前
<P5464 缩小社交圈>
排序算法·预处理·前缀和与差分·动态规划(区间 dp)·快速读入·模运算处理·区间查询与更新
Jasmine_llq1 个月前
《UVA11181 条件概率 Probability|Given》
数据结构·算法·深度优先搜索(dfs)·剪枝(可行性剪枝)·组合枚举(递归暴力枚举)·条件概率统计与归一化
Jasmine_llq1 个月前
《CF280C Game on Tree》
数据结构·算法·邻接表·深度优先搜索(dfs)·树的遍历 + 线性累加统计
Jasmine_llq6 个月前
《CF1120D Power Tree》
动态规划·dp·深度优先搜索(dfs)·广度优先搜索(bfs)·树结构处理技术·状态回溯技术