zoukankan      html  css  js  c++  java
  • BZOJ1566 【NOI2009】管道取珠

    题面

    这是一道DP神题,直到我写下这句题解时也没有想明白……

    首先,这道题要我们求所有(不同输出序列的方案数)的平方和,于是我们当然就想到求所有不同输出序列的方案数……(大雾) 。这道题一个巧妙的地方就在于对问题的转化。(以下摘自BYVoid大神的题解

    假设同时有两个人X & Y在玩这个游戏,Xup取了i个珠子(不一定连续),从down取了j个珠子,取出来的珠子组成的序列为Q操作序列为xYup取了k个珠子,从down取了l个珠子,取出来的珠子组成的序列也为Q操作序列为y,那么我们就得到了一个有序对(xy,f[i][j][k][l]即表示有序对(xy)的数量两个有序对不相同当且仅当xy不同时相同

    下面证明f[i][j][k][l]即为所求。

    已知:取出珠子的序列为Qxy分别为一种取珠方法(可相同), 取出Q的方案数为a

    求证:有序对(xy)的数量等于a2

    因为取出Q的方案数为a,所以x & y都有a种取值,且x & y彼此独立,故对于x的每一个取值,y都有a种取值,故有序对(xy)的数量为a2,命题得证。

    博主是个超级大傻*,连空间优化到n2都不会,请各路大神指教。

     1 #include <map>
     2 #include <set>
     3 #include <cmath>
     4 #include <queue>
     5 #include <stack>
     6 #include <cstdio>
     7 #include <string>
     8 #include <vector>
     9 #include <cstring>
    10 #include <complex>
    11 #include <cstdlib>
    12 #include <iostream>
    13 #include <algorithm>
    14 #define rg register
    15 #define ll long long
    16 using namespace std;
    17 
    18 inline int gi()
    19 {
    20     rg int r = 0; rg bool b = 1; rg char c = getchar();
    21     while (c < '0' || c > '9') { if (c == '-') b = 0; c = getchar(); }
    22     while (c >= '0' && c <= '9') { r = r * 10 + c - '0', c = getchar(); }
    23     if (b) return r; return -r;
    24 }
    25 
    26 const int inf = 2147483647, N = 505, MOD = 1024523;
    27 int n,m,f[N][N][N];
    28 char S[N],X[N];
    29 
    30 inline void input()
    31 {
    32     freopen ("!.in", "r", stdin);
    33     n=gi(), m=gi();
    34     scanf("%s%s",S+1,X+1);
    35 }
    36 
    37 inline void output()
    38 {
    39     freopen ("!.out", "w", stdout);
    40     printf("%d
    ",f[n][m][n]);
    41 }
    42 
    43 inline void cal(int &t,int d) { t+=d; if (t >= MOD) t-=MOD; }
    44 
    45 inline void solve()
    46 {
    47     int i,j,k,l,tmp;
    48     f[0][0][0]=1;
    49     for (i=0; i<=n; i++)
    50         for (j=0; j<=m; j++)
    51             for (k=0; k<=n; k++)
    52                 {
    53                     tmp=f[i][j][k], l=i+j-k;
    54                     if (!tmp || !l || l > m) continue;
    55                     if (S[i+1] == S[k+1])
    56                         cal(f[i+1][j][k+1],tmp);
    57                     if (X[j+1] == S[k+1])
    58                         cal(f[i][j+1][k+1],tmp);
    59                     if (S[i+1] == X[l+1])
    60                         cal(f[i+1][j][k],tmp);
    61                     if (X[j+1] == X[l+1])
    62                         cal(f[i][j+1][k],tmp);
    63                 }
    64 }
    65 
    66 int main()
    67 {
    68     input();
    69     solve();
    70     output();
    71     return 0;
    72 }

     Update

    博主终于会把空间优化到n^2辣!!!

    PS:记得要清零!!!

     1 #include <bits/stdc++.h>
     2 #define rg register
     3 #define ll long long
     4 using namespace std;
     5 
     6 inline int gi()
     7 {
     8     rg int r = 0; rg bool b = 1; rg char c = getchar();
     9     while (c < '0' || c > '9') { if (c == '-') b = 0; c = getchar(); }
    10     while (c >= '0' && c <= '9') { r = r * 10 + c - '0', c = getchar(); }
    11     if (b) return r; return -r;
    12 }
    13 
    14 const int inf = 2147483647, N = 505, MOD = 1024523;
    15 int n,m,f[2][N][N];
    16 char S[N],X[N];
    17 
    18 inline void input()
    19 {
    20     n=gi(), m=gi();
    21     scanf("%s%s",S,X);
    22 }
    23 
    24 inline void cal(rg int &t,rg int d)
    25 {
    26     t+=d;
    27     if (t >= MOD)
    28         t-=MOD;
    29 }
    30 
    31 inline void solve()
    32 {
    33     rg int i,j,k,p,q,l,r,now,lst;
    34     f[0][0][0]=1, now=0;
    35     for (k=0; k<n+m; ++k)   //枚举一共选了多少个,因为每次更新都会多选一个,所以只需枚举到 n+m-1
    36         {
    37             l=max(k-m,0), r=min(k,n);   //计算 S 管道取珠的数量范围
    38             lst=now, now^=1;
    39             for (i=l; i<=r; ++i)   //分别枚举序列 x,y
    40                 for (j=l; j<=r; ++j)
    41                     {
    42                         p=k-i, q=k-j;   //i,j 表示 S 管道取的数量,p,q表示 X 管道的数量
    43                         if (!f[lst][i][j])
    44                             continue;
    45                         if (S[i] == S[j])
    46                             cal(f[now][i+1][j+1],f[lst][i][j]);
    47                         if (S[i] == X[q])
    48                             cal(f[now][i+1][j],f[lst][i][j]);
    49                         if (X[p] == S[j])
    50                             cal(f[now][i][j+1],f[lst][i][j]);
    51                         if (X[p] == X[q])
    52                             cal(f[now][i][j],f[lst][i][j]);
    53                         f[lst][i][j]=0;   //每次更新后要记得清零
    54                     }
    55         }
    56     printf("%d
    ",f[now][n][n]);
    57 }
    58 
    59 int main()
    60 {
    61     input();
    62     solve();
    63     return 0;
    64 }
  • 相关阅读:
    mvc Controller类介绍
    Mvc全局过滤器与Action排除
    MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等
    EF查询数据库框架的搭建
    MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等
    BootstrapTable与KnockoutJS相结合实现增删改查功能
    JSON详解
    Asp.net管道模型(管线模型)
    NET/ASP.NET MVC Controller 控制器(一:深入解析控制器运行原理)
    .NET/ASP.NET Routing路由(深入解析路由系统架构原理)
  • 原文地址:https://www.cnblogs.com/y142857/p/7197649.html
Copyright © 2011-2022 走看看