【BZOJ3167】[Heoi2013]Sao

Description

WelcometoSAO(StrangeandAbnormalOnline)。这是一个VRMMORPG,含有n个关卡。但是,挑战不同关卡的顺序是一个很大的问题。有n–1个对于挑战关卡的限制,诸如第i个关卡必须在第j个关卡前挑战,或者完成了第k个关卡才能挑战第l个关卡。并且,如果不考虑限制的方向性,那么在这n–1个限制的情况下,任何两个关卡都存在某种程度的关联性。即,我们不能把所有关卡分成两个非空且不相交的子集,使得这两个子集之间没有任何限制。

Input

第一行,一个整数T,表示数据组数。对于每组数据,第一行一个整数n,表示关卡数。接下来n–1行,每行为“i sign j”,其中0≤i,j≤n–1且i≠j,sign为“<”或者“>”,表示第i个关卡必须在第j个关卡前/后完成。
T≤5,1≤n≤1000

Output

对于每个数据,输出一行一个整数,为攻克关卡的顺序方案个数,mod1,000,000,007输出。

Sample Input

1
10
5 > 8
5 > 6
0 < 1
9 < 4
2 > 5
5 < 9
8 < 1
9 > 3
1 < 7

Sample Output

2580

题解:憋了一下午想出来的树形DP题~

如何设状态呢?显然应该是个二维的状态。设f[i][j]表示在i的子树中,i位于第j个位置的方案数。那么我们如何将x的当前状态与他的儿子的状态合并呢?

先只考虑x<y的情况,我们设原来的siz[x]=sa,siz[y]=sb,sa+sb=sc,我们想用f[x][a]和f[y][b]来更新f[x][c](c>=a+b),为了区分新的f和旧的f,我们用g[c]表示新的f。

如果x位于位置c,那么它左边有c-1个位置,相当于将y的序列中左边的数与x的序列中左边的数进行了二路归并,并且归并的顺序可以随便确定,那么方案数就是$C_{c-1}^{a-1}$,同理,右面的sc-c个数也可以归并处理,方案数是$C_{sc-c}^{sa-a}$,所以得到方程:

$g[c]=\sum\limits_{a=1}^{c}\sum\limits_{b=1}^{c-a}C_{c-1}^{a-1}C_{sc-c}^{sa-a}f[x][a]*f[y][b]$

可以将f[y][b]提出来

$g[c]=\sum\limits_{b=1}^{c}f[y][b]\sum\limits_{a=1}^{c-b}C_{c-1}^{a-1}C_{sc-c}^{sa-a}f[x][a]$

这个东西就可以用前缀和维护了~

不过值得惭愧的是,我的代码的上界设的不紧,或是循环顺序不太对,复杂度其实应该是O(n^3)的,似乎可以改一改使得复杂度变成树形背包的优雅的O(n^2)。不过还是卡过了,就没有改,求不卡~不过处理4824那题还是很轻松的,因为是完全二叉树嘛~

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. using namespace std;
  5. typedef long long ll;
  6. const ll P=1000000007;
  7. int n,cnt;
  8. ll ans;
  9. ll C[1010][1010];
  10. ll f[1010][1010],g[1010],s[1010];
  11. int to[2010],next[2010],head[1010],val[2010],fa[1010],siz[1010];
  12. char str[5];
  13. void dfs(int x)
  14. {
  15. int i,y,a,b,c;
  16. siz[x]=1,f[x][1]=1;
  17. for(i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x])
  18. {
  19. y=to[i],fa[y]=x,dfs(y);
  20. memset(g,0,sizeof(g[0])*(siz[x]+siz[y]+1));
  21. if(val[i]==1)
  22. {
  23. for(c=2;c<=siz[x]+siz[y];c++)
  24. {
  25. s[max(1,c-siz[y])-1]=0;
  26. for(b=1;b<=min(siz[x],c-1);b++)
  27. s[b]=(s[b-1]+C[c-1][b-1]*C[siz[x]+siz[y]-c][siz[x]-b]%P*f[x][b])%P;
  28. for(a=1;a<=min(siz[y],c-1);a++)
  29. {
  30. if(c-a>min(siz[x],c-1)) s[c-a]=s[min(siz[x],c-1)];
  31. if(c-a<max(1,c-siz[y])) s[c-a]=0;
  32. g[c]=(g[c]+s[c-a]*f[y][a])%P;
  33. }
  34. }
  35. f[x][1]=0;
  36. for(c=2;c<=siz[x]+siz[y];c++) f[x][c]=g[c];
  37. }
  38. else
  39. {
  40. for(c=2;c<=siz[x]+siz[y];c++)
  41. {
  42. s[max(1,c-siz[y])-1]=0;
  43. for(b=1;b<=min(siz[x],c-1);b++)
  44. s[b]=(s[b-1]+C[c-1][b-1]*C[siz[x]+siz[y]-c][siz[x]-b]%P*f[x][siz[x]-b+1])%P;
  45. for(a=1;a<=min(siz[y],c-1);a++)
  46. {
  47. if(c-a>min(siz[x],c-1)) s[c-a]=s[min(siz[x],c-1)];
  48. if(c-a<max(1,c-siz[y])) s[c-a]=0;
  49. g[c]=(g[c]+s[c-a]*f[y][siz[y]-a+1])%P;
  50. }
  51. }
  52. f[x][siz[x]+siz[y]]=0;
  53. for(c=1;c<siz[x]+siz[y];c++) f[x][c]=g[siz[x]+siz[y]-c+1];
  54. }
  55. siz[x]=siz[x]+siz[y];
  56. }
  57. }
  58. inline void add(int a,int b,int c)
  59. {
  60. to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
  61. }
  62. void work()
  63. {
  64. scanf("%d",&n);
  65. int i,a,b;
  66. memset(head,-1,sizeof(head)),cnt=0;
  67. memset(f,0,sizeof(f)),memset(fa,0,sizeof(fa));
  68. for(i=1;i<n;i++)
  69. {
  70. scanf("%d%s%d",&a,str,&b),a++,b++;
  71. if(str[0]=='>') add(a,b,1),add(b,a,0);
  72. if(str[0]=='<') add(a,b,0),add(b,a,1);
  73. }
  74. dfs(1);
  75. ans=0;
  76. for(i=1;i<=n;i++) ans=(ans+f[1][i])%P;
  77. printf("%lld\n",ans);
  78. }
  79. int main()
  80. {
  81. int T,i,j;
  82. C[0][0]=1;
  83. for(i=1;i<=1000;i++)
  84. {
  85. C[i][0]=1;
  86. for(j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
  87. }
  88. scanf("%d",&T);
  89. while(T--) work();
  90. return 0;
  91. }//5 10 5 > 8 5 > 6 0 < 1 9 < 4 2 > 5 5 < 9 8 < 1 9 > 3 1 < 7 10 6 > 7 2 > 0 9 < 0 5 > 9 7 > 0 0 > 3 7 < 8 1 < 2 0 < 4 10 2 < 0 1 > 4 0 > 5 9 < 0 9 > 3 1 < 2 4 > 6 9 < 8 7 > 1 10 0 > 9 5 > 6 3 > 6 8 < 7 8 > 4 0 > 6 8 > 5 8 < 2 1 > 8 10 8 < 3 8 < 4 1 > 3 1 < 9 3 < 7 2 < 8 5 > 2 5 < 6 0 < 9
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. using namespace std;
  5. typedef long long ll;
  6. const ll P=1000000007;
  7. int n,cnt;
  8. ll ans;
  9. ll C[1010][1010];
  10. ll f[1010][1010],g[1010],s[1010];
  11. int to[2010],next[2010],head[1010],val[2010],fa[1010],siz[1010];
  12. char str[5];
  13. void dfs(int x)
  14. {
  15. int i,y,a,b,c;
  16. siz[x]=1,f[x][1]=1;
  17. for(i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[x])
  18. {
  19. y=to[i],fa[y]=x,dfs(y);
  20. memset(g,0,sizeof(g[0])*(siz[x]+siz[y]+1));
  21. if(val[i]==1)
  22. {
  23. for(c=2;c<=siz[x]+siz[y];c++)
  24. {
  25. s[max(1,c-siz[y])-1]=0;
  26. for(b=1;b<=min(siz[x],c-1);b++)
  27. s[b]=(s[b-1]+C[c-1][b-1]*C[siz[x]+siz[y]-c][siz[x]-b]%P*f[x][b])%P;
  28. for(a=1;a<=min(siz[y],c-1);a++)
  29. {
  30. if(c-a>min(siz[x],c-1)) s[c-a]=s[min(siz[x],c-1)];
  31. if(c-a<max(1,c-siz[y])) s[c-a]=0;
  32. g[c]=(g[c]+s[c-a]*f[y][a])%P;
  33. }
  34. }
  35. f[x][1]=0;
  36. for(c=2;c<=siz[x]+siz[y];c++) f[x][c]=g[c];
  37. }
  38. else
  39. {
  40. for(c=2;c<=siz[x]+siz[y];c++)
  41. {
  42. s[max(1,c-siz[y])-1]=0;
  43. for(b=1;b<=min(siz[x],c-1);b++)
  44. s[b]=(s[b-1]+C[c-1][b-1]*C[siz[x]+siz[y]-c][siz[x]-b]%P*f[x][siz[x]-b+1])%P;
  45. for(a=1;a<=min(siz[y],c-1);a++)
  46. {
  47. if(c-a>min(siz[x],c-1)) s[c-a]=s[min(siz[x],c-1)];
  48. if(c-a<max(1,c-siz[y])) s[c-a]=0;
  49. g[c]=(g[c]+s[c-a]*f[y][siz[y]-a+1])%P;
  50. }
  51. }
  52. f[x][siz[x]+siz[y]]=0;
  53. for(c=1;c<siz[x]+siz[y];c++) f[x][c]=g[siz[x]+siz[y]-c+1];
  54. }
  55. siz[x]=siz[x]+siz[y];
  56. }
  57. }
  58. inline void add(int a,int b,int c)
  59. {
  60. to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
  61. }
  62. void work()
  63. {
  64. scanf("%d",&n);
  65. int i,a,b;
  66. memset(head,-1,sizeof(head)),cnt=0;
  67. memset(f,0,sizeof(f)),memset(fa,0,sizeof(fa));
  68. for(i=1;i<n;i++)
  69. {
  70. scanf("%d%s%d",&a,str,&b),a++,b++;
  71. if(str[0]=='>') add(a,b,1),add(b,a,0);
  72. if(str[0]=='<') add(a,b,0),add(b,a,1);
  73. }
  74. dfs(1);
  75. ans=0;
  76. for(i=1;i<=n;i++) ans=(ans+f[1][i])%P;
  77. printf("%lld\n",ans);
  78. }
  79. int main()
  80. {
  81. int T,i,j;
  82. C[0][0]=1;
  83. for(i=1;i<=1000;i++)
  84. {
  85. C[i][0]=1;
  86. for(j=1;j<=i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
  87. }
  88. scanf("%d",&T);
  89. while(T--) work();
  90. return 0;
  91. }//5 10 5 > 8 5 > 6 0 < 1 9 < 4 2 > 5 5 < 9 8 < 1 9 > 3 1 < 7 10 6 > 7 2 > 0 9 < 0 5 > 9 7 > 0 0 > 3 7 < 8 1 < 2 0 < 4 10 2 < 0 1 > 4 0 > 5 9 < 0 9 > 3 1 < 2 4 > 6 9 < 8 7 > 1 10 0 > 9 5 > 6 3 > 6 8 < 7 8 > 4 0 > 6 8 > 5 8 < 2 1 > 8 10 8 < 3 8 < 4 1 > 3 1 < 9 3 < 7 2 < 8 5 > 2 5 < 6 0 < 9

【BZOJ3167/4824】[Heoi2013]Sao/[Cqoi2017]老C的键盘的更多相关文章

  1. 【BZOJ3167】[HEOI2013]SAO(动态规划)

    [BZOJ3167][HEOI2013]SAO(动态规划) 题面 BZOJ 洛谷 题解 显然限制条件是一个\(DAG\)(不考虑边的方向的话就是一棵树了). 那么考虑树型\(dp\),设\(f[i][ ...

  2. [BZOJ4824][CQOI2017]老C的键盘(树形DP)

    4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 193  Solved: 149[Submit][Statu ...

  3. [BZOJ4824][Cqoi2017]老C的键盘 树形dp+组合数

    4824: [Cqoi2017]老C的键盘 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 218  Solved: 171[Submit][Statu ...

  4. [CQOI2017]老C的键盘

    [CQOI2017]老C的键盘 题目描述 额,网上题解好像都是用的一大堆组合数,然而我懒得推公式. 设\(f[i][j]\)表示以\(i\)为根,且\(i\)的权值为\(j\)的方案数. 转移: \[ ...

  5. bzoj 4824: [Cqoi2017]老C的键盘

    Description 老 C 是个程序员.     作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 ...

  6. [bzoj4824][Cqoi2017]老C的键盘

    来自FallDream的博客,未经允许,请勿转载,谢谢. 老 C 是个程序员.     作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序在某种 ...

  7. [bzoj4824][洛谷P3757][Cqoi2017]老C的键盘

    Description 老 C 是个程序员. 作为一个优秀的程序员,老 C 拥有一个别具一格的键盘,据说这样可以大幅提升写程序的速度,还能让写出来的程序 在某种神奇力量的驱使之下跑得非常快.小 Q 也 ...

  8. Luogu P3757 [CQOI2017]老C的键盘

    题目描述 老C的键盘 题解 显然对于每个数 x 都有唯一对应的 \(x/2\) , 然而对于每个数 x 却可以成为 \(x*2\) 和 \(x*2+1\) 的对应数 根据这一特性想到了啥??? 感谢l ...

  9. [BZOJ3167][P4099][HEOI2013]SAO(树形DP)

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

随机推荐

  1. 【BZOJ 2753 滑雪与时间胶囊】

    Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 2843  Solved: 993[Submit][Status][Discuss] Descripti ...

  2. 【BZOJ 2957】楼房重建&&Codechef COT5 Count on a Treap&&【NOIP模拟赛】Weed 线段树的分治维护

    线段树是一种作用于静态区间上的数据结构,可以高效查询连续区间和单点,类似于一种静态的分治.他最迷人的地方在于“lazy标记”,对于lazy标记一般随我们从父区间进入子区间而下传,最终给到叶子节点,但还 ...

  3. SICAU-OJ: A|B

    A|B 题意: 给出一个整数n(1<=n<=10100),求Σd(d满足d可以整除n),同时保证不存在x^2有x^2可以整除n. 另外,n的质因子满足小于等于1000. 题解: 这题是我第 ...

  4. nodejs npm insttall 带不带-g这个参数的区别

    -g 中的g是global的意思所以带-g这个参数是全局安装,不带-g这个参数是本地安装. 在windows系统中全局安装的目录在:C:\Users\linsenq\AppData\Roaming\n ...

  5. bzoj 1110 [POI2007]砝码Odw 贪心+进制转化

    [POI2007]砝码Odw Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 661  Solved: 366[Submit][Status][Disc ...

  6. 新手如何更换自己喜欢的背景以及此背景的css码

    以下内容为转载(对于css码可以自己写当然也可以去网上搜现成的): 更换背景教学:https://jingyan.baidu.com/album/fc07f9897c730412ffe519c0.ht ...

  7. 【poj3294-不小于k个字符串中最长公共子串】后缀数组

    1.注意每两个串之间的连接符要不一样. 2.分组的时候要注意最后一组啊!又漏了! 3.开数组要考虑连接符的数量.100010是不够的至少要101000. #include<cstdio> ...

  8. c:forEach 如何输出序号

    关键在于<c:forEach>的varStatus属性,具体代码如下: <table width="500" border="0" cells ...

  9. MYSQL5.7修改密码

    参考:https://www.cnblogs.com/activiti/p/7810166.html # alter user 'root'@'localhost' identified by '12 ...

  10. Django【进阶】

    FBV和CBV http://www.cnblogs.com/lucaq/p/7565560.html 中间件 http://www.cnblogs.com/lucaq/p/7581234.html ...