zoukankan      html  css  js  c++  java
  • 重庆市队选拔 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 floor $的式子

    $$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 eq i}mu(d) ) \ = 1 - sum_{i=1}^N sum_{d|i land d eq i} mu(d) \= 1 - sum_{i'=2}^N sum_{d=1}^{lfloor frac{N}{i'} floor} mu(d) \ = 1 - sum_{i'=2}^N M(lfloor frac{N}{i'} floor)$$

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

    $lfloor frac{N}{i'} floor$分块递归就可以快速地求出超过$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)$。 

     代码:

     1 /***********************************************************************/
     2 /**********************By Asm.Def-Wu Jiaxin*****************************/
     3 /***********************************************************************/
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <cstdlib>
     7 #include <ctime>
     8 #include <cctype>
     9 #include <algorithm>
    10 #ifdef DEBUG
    11 #include <sys/timeb.h>
    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 <sys/timeb.h>
    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 ", 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(" %.3lf sec  ", (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 可以得到很好的运行效率。

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 #include <ctime>
      5 #include <cctype>
      6 #include <algorithm>
      7 #include <cmath>
      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 <queue>
     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 ", ans);
    125 #ifdef DEBUG
    126     printf(" %.3lf sec  ", (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$

    分析:

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

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 #include <ctime>
      5 #include <cctype>
      6 #include <algorithm>
      7 #include <cmath>
      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 ", Pre);
    104     }
    105     
    106 #ifdef DEBUG
    107     printf(" %.3lf sec  ", (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 binom{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} binom{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的矩阵快速幂。 

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 #include <ctime>
      5 #include <cctype>
      6 #include <algorithm>
      7 #include <cmath>
      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(" %.3lf sec  ", (double)clock() / CLOCKS_PER_SEC);
    100 #endif
    101     return 0;
    102 }
    高精度+十进制矩阵快速幂

     E.标识设计

    题意:

     链接:COGS 1938

    分析:

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

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

     代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <ctime>
     5 #include <cctype>
     6 #include <algorithm>
     7 #include <cmath>
     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 ", dp(0,3,0,0,0));
    85     
    86 #ifdef DEBUG
    87     printf(" %.3lf sec  ", (double)clock() / CLOCKS_PER_SEC);
    88 #endif
    89     return 0;
    90 }
    轮廓线dp(用记忆化搜索实现)
  • 相关阅读:
    git速度慢解决方式
    idea破解
    高并发redis分布式锁
    一个简单的struts2项目
    一个简单的java项目使用hibernate连接mysql数据库
    hibernate连接数据库中文乱码
    删除文件时出现找不到该项目 请确认该项目位置
    redis错误解决
    pyQT4和pyQT5的主要模块介绍
    python之type函数
  • 原文地址:https://www.cnblogs.com/Asm-Definer/p/4434601.html
Copyright © 2011-2022 走看看