重庆市队选拔 CQOI2015 解题报告

文章链接:http://www.cnblogs.com/Asm-Definer/p/4434601.html

题目链接:http://pan.baidu.com/s/1mgxIKli

官方数据:http://pan.baidu.com/s/1qW4wkVE

 

     看巨神们都去虐ZJOI了,蒟蒻只能默默地码着CQOI的题解……

     CQOI的难度分布也是挺神奇的,五小时五道题,三(或四)道水题一两道神题(只是对我来说比较神...),我猜让我去考我一定会写不完D题然后滚去备战高考= =

 

A.选数

 题意:

    从区间[L, H]中选出N个数(可以重复),求取出的N个数的最大公约数恰好为K的方案数。

其中$1 \leq L, H, N \leq 10^9, H - L \leq 10^5$

 分析:

    刚开始还以为这是道简单的莫比乌斯反演题,推了半天公式,发现是个依赖$\lfloor H / K \rfloor $的式子

$$\sum_{d=1}^{H/K} \mu(d) (\frac{H}{d*K} - \frac{L-1}{d*K})^N$$(由于LaTeX打取整式太不方便所以这个式子没有考虑细节)当$H/K$很大的时候mu就无法预处理了。

    后来衡中的JSX同学(http://55242.cf/)告诉我一个不错的思路:对较小的mu用线性筛预处理,对较大的mu直接暴力分解质因数。而当d比较大的时候会有很多$(\frac{H}{d*K} - \frac{L-1}{d*K})$为0的区间,遇到这些区间就跳转一下就可以了。粘一下他的核心代码:

1  for( int i =  1;i <= R;++ i) {
2      if((R/i) == (L/i)) {
3         i = min((LL)R/(R/i) ,(LL)L / i ? L/(L/i) : INF);
4          continue;
5     }  else {
6         ans += (LL)quickpow((R/i)-(L/i),N) * get_mu(i);
7         ans %= mod;
8     }
9 }

    思路简单,效率也很不错。

    不过……有强迫症的同学可能会想……如果这道题表达式的后半部分不是$(\frac{H}{d*K} - \frac{L-1}{d*K})$而只有$\frac{H}{d*K}$,这个式子就不会很快变成0了。这样还是否可做呢?

    考虑到在取整后$\frac{H}{d*K}$的取值只有$\sqrt{\frac{H}{K}}$个,如果我们能快速地求出莫比乌斯的前缀和(梅腾斯函数),就可以在$O(1)$的时间内求出一段相等的区间的贡献了。

    这个$M(N) = \sum_{i=1}^N \mu(i)$看起来似乎很难的样子……其实我们可以这样转化:

$$M(N)= \sum_{i=1}^N (\sum_{d|i}\mu(d) - \sum_{d|i \land d \neq i}\mu(d) ) \\ = 1 - \sum_{i=1}^N \sum_{d|i \land d \neq i} \mu(d) \\= 1 - \sum_{i'=2}^N \sum_{d=1}^{\lfloor \frac{N}{i'} \rfloor} \mu(d) \\ = 1 - \sum_{i'=2}^N M(\lfloor \frac{N}{i'}\rfloor)$$

     这样,我们就只需在预处理出前$10^7$项梅腾斯函数后在处理较大的N时对

$\lfloor \frac{N}{i'}\rfloor$分块递归就可以快速地求出超过$10^7$的梅腾斯函数了。(这个带下取整的递推式复杂度究竟是多少呢……反正我不会分析……不过目测我们需要计算梅腾斯函数的次数非常少,所以这个复杂度已经足够了。

     然而……出题人表示我们都太Simple啦,Sometimes Naive!我们观察一下题目中的条件……“$H - L \leq 10^5$"......注意到当N个数不全相同的时候,它们的最大公约数一定不会超过其中任意两个不同数的差。于是……我们只需要将边界除以K后递推”N个数不全相同且最大公因数为i($i \leq 10^5$)"的方案数,最后特判一下N个数都相同的情况,加上递归得到的F(1)就是答案了,复杂度是优美的$(H-L) log (H-L)$。 

 代码:

ExpandedBlockStart.gif
 1  /* ********************************************************************* */
 2  /* *********************By Asm.Def-Wu Jiaxin**************************** */
 3  /* ********************************************************************* */
 4 #include 
 5 #include 
 6 #include 
 7 #include 
 8 #include 
 9 #include 
10 #ifdef DEBUG
11 #include 
12  #endif
13  using  namespace std;
14  #define SetFile(x) ( freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout) );
15  #define getc() getchar() 
16 template< class T>inline  void getd(T &x){
17      char ch = getc(); bool neg =  false;
18      while(!isdigit(ch) && ch !=  ' - ')ch = getc();
19      if(ch ==  ' - ')ch = getc(), neg =  true;
20     x = ch -  ' 0 ';
21      while(isdigit(ch = getc()))x = x *  10 -  ' 0 ' + ch;
22      if(neg)x = -x;
23 }
24 #ifdef DEBUG
25 #include 
26 timeb Tp;
27  #endif
28  /* ********************************************************************* */
29  const  int maxn =  100004, mod =  1000000007;
30 typedef  long  long LL;
31 inline  int powmod( int a,  int n){
32      int ans =  1;
33      while(n){ if(n &  1)ans = (LL)ans * a % mod;a = (LL)a * a % mod;n >>=  1;}
34      return ans;
35 }
36 
37 inline  void work(){
38      int f[maxn], N, K, L, H, i, j, t, *it;getd(N), getd(K), getd(L), getd(H);
39     L = (L -  1) / K;H /= K;
40      int len = H - L;
41      for(i = len, it = f + i;i;--i, --it){
42         t = H / i - L / i; // 澶氬皯涓猧鐨勫€嶆暟
43          *it = (powmod(t, N) + mod - t) % mod;
44          for(j = i <<  1;j <= len;j += i)
45             *it = (*it + mod - f[j]) % mod;
46     }
47      if(L <=  1 && H >  1)++f[ 1];
48     printf( " %d\n ", f[ 1]);
49 }
50 
51  int main(){
52 
53 #ifdef DEBUG
54     freopen( " test.txt "" r ", stdin);
55     ftime(&Tp);
56     time_t Begin_sec = Tp.time, Begin_mill = Tp.millitm;
57  #elif !defined ONLINE_JUDGE
58     SetFile(cqoi15_number);
59  #endif
60     work();
61 
62 #ifdef DEBUG
63     ftime(&Tp);
64     printf( " \n%.3lf sec \n ", (Tp.time - Begin_sec) + (Tp.millitm - Begin_mill) /  1000.0);
65  #endif
66      return  0;
67 }
A.递推

 B.网络吞吐量

题意:

    在一个无向网络的最短路径构成的DAG上求最大流。

$|V| \leq 500, |E| \leq 100000 $ 

分析:

似乎不需要分析了,除了最短路+网络流外没有什么其他的东西……

注意到这里的原图是个稠密图,使用$O(|V|^2)$的Dijkstra 可以得到很好的运行效率。

代码:

ExpandedBlockStart.gif
  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8  using  namespace std;
  9  #define USEFREAD
 10 #ifdef USEFREAD
 11  #define InputLen 5000000
 12  char *ptr=( char *) malloc(InputLen);
 13  #define getc() (*(ptr++))
 14  #else
 15  #define getc() (getchar())
 16  #endif
 17  #define SetFile(x) (freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout))
 18 template< class T>inline  void getd(T &x){
 19      char ch = getc(); bool neg =  false;
 20      while(!isdigit(ch) && ch !=  ' - ')ch = getc();
 21      if(ch ==  ' - ')ch = getc(), neg =  true;
 22     x = ch -  ' 0 ';
 23      while(isdigit(ch = getc()))x = x *  10 -  ' 0 ' + ch;
 24      if(neg)x = -x;
 25 }
 26  /* ********************************************************************* */
 27  const  int maxn =  512, maxv =  1003;
 28 typedef  long  long LL;
 29  const LL INF = 0x3f3f3f3f3f3f3f3fll;
 30  int S, N, tmp[maxn][maxn], tmpcnt[maxn], val[maxn];
 31 LL dis[maxn], G[maxn][maxn];
 32 inline  void init(){
 33      int M, i, u, v, d, *t = val +  1;
 34     getd(N), getd(M);S =  1 + N;
 35      while(M--){
 36         getd(u), getd(v), getd(d);LL &e = G[u][v];
 37          if(!e || e > d)e = d, G[v][u] = d;
 38     }
 39      for(i =  1;i <= N;++i, ++t)getd(*t);
 40 }
 41 
 42  struct Edge{
 43      int to, vol;Edge *op;
 44     inline  void init( int t,  int v, Edge *o){to = t, vol = v, op = o;}
 45 }adj[maxv][maxn]; int adjcnt[maxv];
 46 
 47 inline  void AddE( int u,  int v,  int vol){
 48      int &itu = adjcnt[u], &itv = adjcnt[v];
 49     adj[u][itu].init(v, vol, adj[v] + itv);adj[v][itv].init(u,  0, adj[u] + itu);++itu, ++itv;
 50 }
 51 
 52 inline  void Dij(){
 53     memset(dis, INF,  sizeof(dis));dis[ 1] =  0;
 54      bool tab[maxn] = { 0}, inS[maxn] = { 0, 1};
 55      int tablist[maxn], *tabiter = tablist, i, j, v, *it, *tmpt;
 56     LL *tmpd, *e, t;
 57      for(i =  2,e = G[ 1]+ 2,tmpd = dis+ 2;i <= N;++i,++e,++tmpd) if(*e)
 58         *(tabiter++) = i, *tmpd = *e, tmp[i][tmpcnt[i]++] =  1;
 59      for(j =  2;j <= N;++j){
 60          if(tabiter == tablist) break;
 61         t = INF;
 62          for(it = tablist;it < tabiter;++it) if(dis[*it] < t)
 63             tmpt = it, t = dis[*it];
 64         inS[v = *(it = tmpt)] =  true;
 65         e = G[v] +  2;
 66         swap(*it, *(--tabiter));
 67          for(i =  2,tmpd = dis+ 2;i <= N;++i,++e,++tmpd) if(*e && !inS[i]){
 68              if(*tmpd > t + *e){
 69                 *tmpd = t + *e;
 70                 *tmp[i] = v;tmpcnt[i] =  1;
 71                  if(!tab[i])*(tabiter++) = i, tab[i] =  true;
 72             }
 73              else  if(*tmpd == t + *e)
 74                 tmp[i][tmpcnt[i]++] = v;
 75         }
 76     }
 77      for(i =  2;i <= N;++i) for(it = tmp[i] + tmpcnt[i] -  1;it >= tmp[i];--it)
 78         AddE(*it + N, i, INF);
 79      for(i =  1;i <= N;++i)AddE(i, i + N, val[i]);
 80 }
 81 
 82  int dep[maxv], curadj[maxv];
 83 LL dfs( int cur, LL f){
 84      if(cur == N) return f;
 85     LL d = dep[cur], ans =  0, t;
 86      int &adjit = curadj[cur];
 87     Edge *it;
 88      for(;adjit < adjcnt[cur];++adjit) if((it = adj[cur]+adjit)->vol && dep[it->to] == d +  1){
 89         t = dfs(it->to, min(f, (LL)it->vol));
 90         it->vol -= t, it->op->vol += t, ans += t, f -= t;
 91          if(!f) return ans;
 92     }
 93      return ans;
 94 }
 95 #include 
 96 inline  bool bfs(){
 97     memset(curadj,  0sizeof(curadj));
 98     queue< int> Q; bool vis[maxv] = { 0};vis[S] =  true;
 99     Q.push(S);
100      int v;LL d;
101     Edge *it, *end;
102      while(!Q.empty()){
103         v = Q.front();Q.pop();d = dep[v];
104          for(it = adj[v],end = it + adjcnt[v];it < end;++it) if(it->vol && !vis[it->to])
105             dep[it->to] = d +  1, Q.push(it->to), vis[it->to] =  true;
106     }
107      return vis[N];
108 }
109 
110  int main(){
111     #ifdef DEBUG
112     freopen( " test.txt "" r ", stdin);
113      #else
114     SetFile(cqoi15_network);
115      #endif
116     #ifdef USEFREAD
117     fread(ptr, 1,InputLen,stdin);
118      #endif
119     init();
120     Dij();
121     LL ans =  0;
122      while(bfs())
123         ans += dfs(S, INF);
124     printf( " %lld\n ", ans);
125 #ifdef DEBUG
126     printf( " \n%.3lf sec \n ", ( double)clock() / CLOCKS_PER_SEC);
127  #endif
128      return  0;
129 }
dijkstra+dinic

 C.任务查询系统

题意:

    给出n个区间,每个区间有一个权值$P_i$;共m次询问,每次询问覆盖$x_i$点的所有区间中权值最小的$K_i$个区间的权值和。

    数据规模 $\leq 10^5$

分析:

    很经典的可持久化线段树的模型。对所有权值离散化后在所有点构造可持久化线段树,询问时对线段树做区间查询。

代码:

ExpandedBlockStart.gif
  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8  using  namespace std;
  9  #define USEFREAD
 10 #ifdef USEFREAD
 11  #define InputLen 4000000
 12  char *ptr=( char *) malloc(InputLen);
 13  #define getc() (*(ptr++))
 14  #else
 15  #define getc() (getchar())
 16  #endif
 17  #define SetFile(x) (freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout))
 18 template< class T>inline  void getd(T &x){
 19      char ch = getc(); bool neg =  false;
 20      while(!isdigit(ch) && ch !=  ' - ')ch = getc();
 21      if(ch ==  ' - ')ch = getc(), neg =  true;
 22     x = ch -  ' 0 ';
 23      while(isdigit(ch = getc()))x = x *  10 -  ' 0 ' + ch;
 24      if(neg)x = -x;
 25 }
 26  /* ********************************************************************* */
 27  const  int maxn =  100004;
 28 typedef  long  long LL;
 29  struct Event{ bool Add; int Time, P;}E[maxn <<  1], *Eend = E;
 30 inline  bool  operator < ( const Event &a,  const Event &b){ return a.Time < b.Time;}
 31 
 32  int Plist[maxn], *Pend = Plist;
 33  #define id(x) (lower_bound(Plist, Pend, x) - Plist)
 34 
 35  struct SegT *Pool;
 36  struct SegT{
 37      int L, R, cnt, mid;
 38     LL Sum;
 39     SegT *ls, *rs;
 40     inline  void init( int l,  int r){
 41         L = l, R = r, mid = (L + R) >>  1;
 42          if(r - l ==  1) return;
 43         ls = Pool++;rs = Pool++;
 44         ls->init(L, mid), rs->init(mid, R);
 45     }
 46      void Add( int i,  int d){
 47          if(R - L ==  1){cnt += d;Sum += Plist[L] * d; return;}
 48         SegT *t = Pool++;
 49          if(i < mid)*t = *ls, t->Add(i, d), ls = t;
 50          else *t = *rs, t->Add(i, d), rs = t;
 51         cnt += d;Sum += d * Plist[i];
 52     }
 53     LL Query( int K){
 54          if(R - L ==  1) return (LL)K * Plist[L];
 55          if(K >= cnt) return Sum;
 56          if(K <= ls->cnt) return ls->Query(K);
 57          return ls->Sum + rs->Query(K - ls->cnt);
 58     }
 59 }Root[maxn *  90];
 60 
 61 inline  int init(){
 62      int i, M, N, L, R, P;
 63     Event *it;
 64     getd(M), getd(N);
 65     Pool = Root + N +  1;
 66      while(M--){
 67         getd(L), getd(R), getd(P);
 68         *(Pend++) = P;
 69         *(Eend++) = (Event){ true, L, P};
 70         *(Eend++) = (Event){ false, R +  1, P};
 71     }
 72     Eend->Time = maxn;
 73     sort(E, Eend);
 74     sort(Plist, Pend);
 75     Root->init( 0, Pend - Plist);
 76     SegT *u = Root, *v = Root +  1;
 77      for(i =  1, it = E;i <= N;++i){
 78         *(v++) = *(u++);
 79          while(it->Time == i){
 80             u->Add(id(it->P),  2 * it->Add -  1);
 81             ++it;
 82         }
 83     }
 84      return N;
 85 }
 86 
 87  int main(){
 88     #ifdef DEBUG
 89     freopen( " test.txt "" r ", stdin);
 90      #else
 91     SetFile(cqoi15_query);
 92      #endif
 93     #ifdef USEFREAD
 94     fread(ptr, 1,InputLen,stdin);
 95      #endif
 96     
 97      int X, A, B, C, N;
 98     LL Pre =  1;
 99     N = init();
100      while(N--){
101         getd(X), getd(A), getd(B), getd(C);
102         Pre = Root[X].Query((Pre * A + B) % C +  1);
103         printf( " %lld\n ", Pre);
104     }
105     
106 #ifdef DEBUG
107     printf( " \n%.3lf sec \n ", ( double)clock() / CLOCKS_PER_SEC);
108  #endif
109      return  0;
110 }
可持久化线段树

 D.多项式

题意:

已知整数$n, t, a_k(1 \leq k \leq n),  m,$ 求出能使$$\sum_{k=0}^n a_k x^k = \sum_{k=1}^n b_k (x-t)^k $$的b数列的第m项。

其中 $a_k$满足递推式:$$k = 0时,a_k = 1;k > 0时,a_k = (1234*a_{k-1} + 5678) \mod 3389$$.

其中 $0 < n \leq 10^{3000}, 0 \leq t \leq 10000, 0 \leq n-m \leq 5.$

分析:

    天哪……为何这位出题人这么喜欢加这么奇怪的数据范围限制……

    首先,对于多项式来说,这个x的取值是任意的。所以我们可以用x+t替换x代入条件,得到

$$\sum_{k=0}^n a_k (x + t)^k = \sum_{k=0}^n b_k x^k$$

$$ \sum_{k=0}^n b_k x^k = \sum_{k=0}^n a_k \sum_{j=0}^k \tbinom{j}{k} x^j t^{k-j} $$

    考虑枚举k-j的值:$$\sum_{k=0}^n b_k x^k=\sum_{i=0}^n \sum_{d=0}^{n-i} a_{i+d} \tbinom{i}{i+d} t^d x^i $$

对齐每一项的系数,得到:

$$b_m = \sum_{d=0}^{n-m} a_{m+d} \frac{(m+d)! t^d}{m!d!}$$

    注意到n-m不超过5,我们可以先得出$a_m$的值,递推(n-m)次把答案加起来即可。

    考虑到n和m都可以很大,这里在求$a_m$的值时要用到10-based的矩阵快速幂。 

代码:

ExpandedBlockStart.gif
  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8  using  namespace std;
  9  // #define USEFREAD
 10  #ifdef USEFREAD
 11  #define InputLen 1000000
 12  char *ptr=( char *) malloc(InputLen);
 13  #define getc() (*(ptr++))
 14  #else
 15  #define getc() (getchar())
 16  #endif
 17  #define SetFile(x) (freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout))
 18 template< class T>inline  void getd(T &x){
 19      char ch = getc(); bool neg =  false;
 20      while(!isdigit(ch) && ch !=  ' - ')ch = getc();
 21      if(ch ==  ' - ')ch = getc(), neg =  true;
 22     x = ch -  ' 0 ';
 23      while(isdigit(ch = getc()))x = x *  10 -  ' 0 ' + ch;
 24      if(neg)x = -x;
 25 }
 26  /* ********************************************************************* */
 27 typedef unsigned  uint;
 28  const  uint mod =  3389, maxn =  10000base =  10000;
 29  uint t, dmax, An;
 30 
 31  struct BigNum;
 32  /* *******************************************
 33  ***************高精度模板略****************
 34  ******************************************* */
 35 
 36  struct Mat{ uint a, b, c, d;Mat( uint w, uint x, uint y, uint z):a(w),b(x),c(y),d(z){}}F( 1234, 0, 2289, 1);
 37 inline  void  operator *= (Mat &x,  const Mat &y){
 38      uint a = (x.a * y.a + x.b * y.c) % mod,
 39         b = (x.a * y.b + x.b * y.d) % mod,
 40         c = (x.c * y.a + x.d * y.c) % mod,
 41         d = (x.c * y.b + x.d * y.d) % mod;
 42     x = Mat(a, b, c, d);
 43 }
 44 
 45 inline Mat powmod(Mat a,  uint n){
 46     Mat ans( 1, 0, 0, 1);
 47      while(n){
 48          if(n &  1)ans *= a;
 49         a *= a;
 50         n >>=  1;
 51     }
 52      return ans;
 53 }
 54 inline Mat powmod(Mat a,  const BigNum &n){
 55  // 其实应该叫“万进制快速幂”……23333
 56       const  int *it = n.a, *end = it + n.len;
 57     Mat ans( 1, 0, 0, 1);
 58      while(it < end){
 59          if(*it)ans *= powmod(a, *it);
 60         a = powmod(a,  base);
 61         ++it;
 62     }
 63      return ans;
 64 }
 65 
 66 inline  void init(){
 67     cin >> N;getd(t);cin >> M;
 68      int tmp = *N.a - *M.a; if(tmp <  0)tmp +=  base;
 69     dmax = tmp;
 70     Mat tf = powmod(F, M);
 71     An = (tf.a + tf.c) % mod;
 72 }
 73 
 74 inline  void work(){
 75     BigNum Ans = An;
 76      uint d;
 77      for(d =  1;d <= dmax;++d){
 78         fd = (fd * (M + d) * t) / d;
 79         An = (An *  1234 +  2289) % mod;
 80         Ans = Ans + fd * An;
 81     }
 82     Ans.print();
 83 }
 84 
 85  int main(){
 86     #ifdef DEBUG
 87     freopen( " test.txt "" r ", stdin);
 88      #else
 89     SetFile(cqoi15_polynomial);
 90      #endif
 91     #ifdef USEFREAD
 92     fread(ptr, 1,InputLen,stdin);
 93      #endif
 94     
 95     init();
 96     work();
 97     
 98 #ifdef DEBUG
 99     printf( " \n%.3lf sec \n ", ( double)clock() / CLOCKS_PER_SEC);
100  #endif
101      return  0;
102 }
高精度+十进制矩阵快速幂

 E.标识设计

题意:

 链接:COGS 1938

分析:

    我真的是昨天才知道这个“标识”的“识”应该念zhi(4)……我真是文盲……

    思路是轮廓线dp,dp状态记录扫描到某个位置时“是否需要连接左边的方格”,“当前已经放下了多少个L”和当前的轮廓。(这里“轮廓”的含义是有哪些列需要连接上方垂下来的竖直线)。由于任意状态垂下来的竖直线最多只有3条,轮廓的状态数很少(暴力枚举一下发现只有4090左右),可以利用离散化减少压位的数量。但以我极差的代码能力实在卡不进1s的时间限制……看了这位神犇的博客之后才知道上述的状态中“不合法状态”和“不可能到达的状态”都很多,所以用记忆化搜索来实现可以大大缩短枚举的时间。

 代码:

ExpandedBlockStart.gif
 1 #include 
 2 #include 
 3 #include 
 4 #include 
 5 #include 
 6 #include 
 7 #include 
 8  using  namespace std;
 9  #define USEFREAD
10 #ifdef USEFREAD
11  #define InputLen 1000
12  char CHARPOOL[InputLen], *ptr=CHARPOOL;
13  #define getc() (*(ptr++))
14  #else
15  #define getc() (getchar())
16  #endif
17  #define SetFile(x) (freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout))
18 template< class T>inline  void getd(T &x){
19      char ch = getc(); bool neg =  false;
20      while(!isdigit(ch) && ch !=  ' - ')ch = getc();
21      if(ch ==  ' - ')ch = getc(), neg =  true;
22     x = ch -  ' 0 ';
23      while(isdigit(ch = getc()))x = x *  10 -  ' 0 ' + ch;
24      if(neg)x = -x;
25 }
26  /* ********************************************************************* */
27 typedef  long  long LL;
28 LL f[ 4][ 4095][ 2][ 31][ 31], Ans; // f[放了几个][列覆盖状态][是否要向右延伸][x][y] = 方案数
29  int N, M, ST[ 4096], Scnt =  1;
30  #define id(x) (lower_bound(ST, ST + Scnt, x) - ST)
31  #define bin(x) (1 << x)
32  bool G[ 31][ 31];
33 
34 inline  void init(){
35     getd(N), getd(M);
36     memset(f, - 1sizeof(f));
37      int i, j, k;
38      for(i =  0;i < N;++i){
39          while((k = getc()) !=  ' . ' && k !=  ' # ');
40          for(j =  0;j < M;++j){
41             G[i][j] = (k ==  ' # ');
42             k = getc();
43         }
44     }
45      for(i =  0;i+ 1 < M;++i){
46         ST[Scnt++] = bin(i);
47          for(j =  0;j < i;++j){
48             ST[Scnt++] = bin(i) | bin(j);
49              for(k =  0;k < j;++k)ST[Scnt++] = bin(i) | bin(j) | bin(k);
50         }
51     }
52 }
53 LL dp( bool lk,  int cnt,  int i,  int j,  int St){
54     LL &ans = f[cnt][St][lk][i][j];
55      if(~ans) return ans;
56     ans =  0;
57      if(i == N) return ans = (!lk && !St && !cnt);
58      if(j == M){ if(!lk)ans = dp( 0,cnt,i+ 1, 0,St); return ans;}
59     register  int b = bin(j), st = ST[St];
60      if(lk && (b & st)) return  0;
61      if(lk){ // from left
62           if(G[i][j]) return  0;
63          return ans = dp( 0,cnt,i,j+ 1,St) + dp( 1,cnt,i,j+ 1,St);
64     }
65      if(b & st){ // from above
66           if(G[i][j]) return  0;
67          return ans = dp( 1,cnt,i,j+ 1,id(st^b)) + dp( 0,cnt,i,j+ 1,St);
68     }
69     ans = dp( 0,cnt,i,j+ 1,St); // skip 
70       if(!G[i][j] && cnt && j+ 1 < M)ans += dp( 0,cnt- 1,i,j+ 1,id(st^b)); //  new
71       return ans;
72 }
73 
74  int main(){
75     #ifdef DEBUG
76     freopen( " test.txt "" r ", stdin);
77      #else
78     SetFile(cqoi15_logo);
79      #endif
80     #ifdef USEFREAD
81     fread(ptr, 1,InputLen,stdin);
82      #endif
83     init();
84     printf( " %lld\n ", dp( 0, 3, 0, 0, 0));
85     
86 #ifdef DEBUG
87     printf( " \n%.3lf sec \n ", ( double)clock() / CLOCKS_PER_SEC);
88  #endif
89      return  0;
90 }
轮廓线dp(用记忆化搜索实现)

 

 

转载于:https://www.cnblogs.com/Asm-Definer/p/4434601.html

你可能感兴趣的:(重庆市队选拔 CQOI2015 解题报告)