NOI前做题记录

  快NOI了还啥都不会,蛤蛤要梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒梅勒。

  为什么我的键盘还不到还不到还不到还不到还不到还不到还不到还不到。

  不一定每道题都写,不一定写的很清楚,各位无聊的时候可以看着玩玩,咕咕咕。

 

白金元首与莫斯科

  比较巧妙的题目,顺着倒着分别轮廓线dp,在障碍处拼起来。因为空格子可能非常麻烦,所以将其视为1*1的小方格,这样就只有目前考虑的轮廓线可能有空了。当两个轮廓拼起来时,所有空格就必须填上,所以轮廓线必须相应对上,才能用竖直方格填满。

  
  1 # include <cstdio>
  2 # include <iostream>
  3 # define R register int
  4 
  5 using namespace std;
  6 
  7 const int N=20;
  8 const int Q=(1<<17)+100;
  9 const int mod=1000000007;
 10 int n,m,q,a[N][N],bit[N];
 11 int f[N][N][Q],g[N][N][Q];
 12 
 13 void add (int &a,int b)
 14 {
 15     a+=b;
 16     if(a>=mod) a-=mod;
 17 }
 18 
 19 int ask (int i,int j)
 20 {
 21     int ans=0;
 22     for (R k=0;k<=q;++k)
 23         if(k&bit[j])
 24         add(ans,1LL*f[i][j-1][k]*g[i][j+1][k]%mod);
 25     return ans;
 26 }
 27 
 28 int main()
 29 {
 30     scanf("%d%d",&n,&m);
 31     for (R i=1;i<=m;++i) bit[i]=1<<(i-1);
 32     for (R i=1;i<=n;++i)
 33         for (R j=1;j<=m;++j)
 34             scanf("%d",&a[i][j]);
 35     q=(1<<m)-1;
 36     f[1][0][q]=1;
 37     for (R i=1;i<=n;++i)
 38         for (R j=1;j<=m;++j)
 39         {
 40             for (R k=0;k<=q;++k)
 41             {
 42                 int t=f[i][j-1][k];
 43                 if(t==0) continue;
 44                 if((k&bit[j])==0)
 45                 {
 46                     if(a[i][j]) continue; //上面那个一定不能空,否则永远填不上
 47                     add(f[i][j][ k|bit[j] ],t);
 48                     continue;
 49                 }
 50                 if(a[i][j]) add(f[i][j][k],t);
 51                 else
 52                 {
 53                     add(f[i][j][k],t);
 54                     add(f[i][j][k^bit[j]],t);
 55                     if(j!=1&&(k&bit[j-1])==0) add(f[i][j][ k|bit[j-1] ],t);
 56                 }
 57             }
 58             if(j==m)
 59             {
 60                 for (R k=0;k<=q;++k) 
 61                     f[i+1][0][k]=f[i][j][k];
 62             }
 63         }
 64     g[n][m+1][q]=1;
 65     for (R i=n;i>=1;--i)
 66         for (R j=m;j>=1;--j)
 67         {
 68             for (R k=0;k<=q;++k)
 69             {
 70                 int t=g[i][j+1][k];
 71                 if(!t) continue;
 72                 if((k&bit[j])==0)
 73                 {
 74                     if(a[i][j]) continue;
 75                     add(g[i][j][ k|bit[j] ],t);
 76                     continue;
 77                 }
 78                 if(a[i][j]) add(g[i][j][k],t);
 79                 else
 80                 {
 81                     add(g[i][j][k],t);
 82                     add(g[i][j][k^bit[j]],t);   
 83                     if(j!=m&&(k&bit[j+1])==0)
 84                         add(g[i][j][k|bit[j+1]],t);
 85                 }
 86             }
 87             if(j==1)
 88             {
 89                 for (R k=0;k<=q;++k)
 90                     g[i-1][m+1][k]=g[i][j][k];
 91             }
 92         }
 93     for (R i=1;i<=n;++i)
 94     {
 95         for (R j=1;j<=m;++j)
 96         {
 97             if(a[i][j]) printf("0 ");
 98             else printf("%d ",ask(i,j));
 99         }
100         printf("\n");
101     }
102     return 0;
103 }
code

 

喂鸽子

  min-max容斥,由于每只鸽子是平等的,不用枚举集合,只要枚举集合的大小就可以了。设 $g(i)$ 表示有i只鸽子的情况下,第一次有鸽子吃饱的期望时间,则 $ans=\sum_{i=1}^n(-1)^{i+1}\binom{n}{i}g(i)$;

  设 $P(n,x=i)$ 表示 $n$ 只鸽子在 $i$ 时刻第一次有某只吃饱的概率,则有:$g(n)=\sum_{i=1}^{\infin}i\times P(n,i)$,也可以转化为 $g(n)=\sum_{i=1}^{\infin} P(n,x\geq i)$。

  设 $f(i,j)$ 表示 $i$ 只鸽子,喂了 $j$ 个玉米,但是每只都没吃饱的概率。

 

如何优雅地求和

  假装我们已经将f变成了一个下降幂多项式,即:$f(x)=\sum_{i=0}^m f_ix^{\underline{i}}$;

  那么$\begin{align} ans&=\sum_{i=0}^mf_i\sum_{k=0}^nk^{\underline{i}}\binom{n}{k}x^k(1-x)^{n-k}\\ &=\sum_{i=0}^mf_i\sum_{k=0}^n\frac{k!}{(k-i)!}\frac{n!}{k!(n-k)!}x^k(1-x)^{n-k}\\ &=\sum_{i=0}^mf_i\sum_{k=0}^n\frac{n!}{(k-i)!(n-k)!}x^k(1-x)^{n-k}   \\ &=\sum_{i=0}^mf_in^{\underline{i}}x^{i}\sum_{k=0}^n\binom{n-i}{k-i}x^{k-i}(1-x)^{n-k}\\ &=\sum_{i=0}^mf_in^{\underline{i}}x^{i}(x+1-x)^{n-i}\\&=\sum_{i=0}^mf_in^{\underline{i}}x^{i}\end{align}$

  那么现在的问题就是怎么转化出下降幂多项式了。

 

一个有意思的小技巧

  $\% 2$ 意义下的多项式的平方很好求,把每一项的指数都乘二就好啦,就是说 $f_ix^i->f_ix^{2i}$;为什么呢?因为对于任意的 $f_ax^a\times f_b x^b(a\neq b)$ 必然对应一组 $f_bx^b\times f_a x^a$,所以系数一定是二的倍数,所以就只用考虑 $f_ix^i\times f_ix^i$ 这样的项。

 

  挺好,看来我是大鸽子,已经8.15了也没写多少blog,那就更新一个打模板记录吧。

  1.堆:没啥好说的,直接priority_queue;

  2.缩点:将栈中的点缩成大点时,别忘了把栈顶弹出(即while(sta[tp]!=x)之后,再加一个tp--);

  3.

posted @ 2020-07-24 18:13  shzr  阅读(238)  评论(0编辑  收藏  举报