【dp】Codeforces R167E.Dima and Figure

http://www.codeforces.com/contest/273/problem/D

  给去一个 n*m的矩阵,让我们在其中去若干个块,使得其满足一下两个条件,A所有块连成一个整体,B.取出的块中任意两个(x1,y1),(x2,y2),可以通过其他块到达且最短路长度是abs(x1-x2)+abs(y1-y2),问一共有多少种取法。

  稍微画一下可以发现对于某行,其被取的块必然是连在一起的,否则条件B显然不成立。所以用dp[i][j][k]表示状态,代表第i行取 第j~k块。

  之后再考虑到要满足如果某行相对上一行j坐标出现向右偏移的情况,则以后j不能再向左偏移,否则B条件不成立。同理k坐标也有同样的性质。可以将状态扩充成dp[i][j][k][sta]。。其中sta是0~3的数字表示j向右偏移,和 k向左偏移是否已经出现过。。到此可以得到一个很暴力的O(n^5) 的做法,如下

View Code
 1     for (int i = 1; i<=n; i++) 
 2         for (int j = 1; j<=m; j++){
 3             for (int k = j; k<=m; k++){
 4                 dp1[i][j][k][0] += 1;
 5                 dp1[i][j][k][0] %= MOD;
 6                 Rep(c,4) { ans += dp1[i][j][k][c]; ans %= MOD; }
 7                 for (int g = 1; g<=m; g++)
 8                     for (int h = g; h<=m; h++){
 9                         if ( max(j,g) > min(k,h) ) continue; 
10                         int sta = 0 , p = 0;
11                         if ( g > j ) sta += 1;
12                         if ( h < k ) sta += 2;
13                         if ( g < j ) p += 1;
14                         if ( h > k ) p += 2;
15                         for (int c = 0; c<4; c++){
16                             if ( c&p ) continue;
17                             dp1[i+1][g][h][c|sta] += dp1[i][j][k][c];
18                             dp1[i+1][g][h][c|sta] %= MOD;
19                         }
20                     }
21             }
22         }

 验证一下小数据发现该dp是正确的,但是对于n<=150显然不足以AC,需要再优化,这里可以采用累加的方法将复杂度降到O(n^3), 比如dp[i][j][k][0] 对比其于dp[i][j][k-1][0],发现其差异 再我们按一定方法枚举j,k时,是可以利用上次运算的结果累加得到的。 同理分析,可以得到1,2,3的O(n^3)算法,详见程序。

View Code
  1 //By Lin
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<set>
  6 #include<map>
  7 #include<queue>
  8 
  9 #define sqr(x) ((x)*(x))
 10 #define MOD 1000000007
 11 #define Rep(i,n) for(int i = 0; i<n; i++)
 12 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++)
 13 #define X first
 14 #define Y second
 15 #define mp(x,y) make_pair(x,y)
 16 
 17 using namespace std;
 18 typedef long long LL;
 19 typedef pair<int,int> pii;
 20 
 21 #define N 155
 22 int        n,m,dp[N][N][N][4];
 23 int        main(){
 24     scanf("%d%d", &n, &m );
 25     int ans = 0, ecnt = 0;
 26 //    for (int i = 1; i<=n; i++) 
 27 //        for (int j = 1; j<=m; j++){
 28 //            for (int k = j; k<=m; k++){
 29 //                dp1[i][j][k][0] += 1;
 30 //                dp1[i][j][k][0] %= MOD;
 31 //                Rep(c,4) { ans += dp1[i][j][k][c]; ans %= MOD; }
 32 //                for (int g = 1; g<=m; g++)
 33 //                    for (int h = g; h<=m; h++){
 34 //                        if ( max(j,g) > min(k,h) ) continue; 
 35 //                        int sta = 0 , p = 0;
 36 //                        if ( g > j ) sta += 1;
 37 //                        if ( h < k ) sta += 2;
 38 //                        if ( g < j ) p += 1;
 39 //                        if ( h > k ) p += 2;
 40 //                        for (int c = 0; c<4; c++){
 41 //                            if ( c&p ) continue;
 42 //                            dp1[i+1][g][h][c|sta] += dp1[i][j][k][c];
 43 //                            dp1[i+1][g][h][c|sta] %= MOD;
 44 //                        }
 45 //                    }
 46 //            }
 47 //        }
 48 //
 49 //    printf("%d\n" , ans );
 50     ans = 0; 
 51     memset( dp , 0 , sizeof(dp) );
 52     int    last[N];
 53     for (int i = 1; i<=n; i++) {
 54         memset( last , 0 , sizeof(last) );
 55         for (int L = 1; L<=m; L++){
 56             for (int j = 1; j+L-1<=m; j++){
 57                 int k = j+L-1;
 58                 dp[i][j][k][0] = dp[i][j][k-1][0];
 59                 last[k] += dp[i-1][j][k][0];
 60                 last[k] %= MOD;
 61                 dp[i][j][k][0] += last[k];
 62                 dp[i][j][k][0] %= MOD;
 63                 if ( L == 1 ) dp[i][j][k][0] = i;
 64             }
 65         }
 66     }
 67     for (int i = 1; i<=n; i++) {
 68         memset( last , 0 , sizeof(last) );
 69         for (int j = 1; j<=m; j++){
 70             for (int k = j; k<=m; k++ ) {
 71                 dp[i][j][k][1] = dp[i][j][k-1][1];
 72                 last[k] += dp[i-1][j][k][1];
 73                 last[k] %= MOD;
 74                 last[k] += dp[i-1][j-1][k][0];
 75                 last[k] %= MOD;
 76                 dp[i][j][k][1] += last[k];
 77                 dp[i][j][k][1] %= MOD;
 78             }
 79         }
 80     }
 81     for (int i = 1; i<=n; i++) {
 82         for (int j = 1; j<=m; j++){
 83             for (int k = j; k<=m; k++ ) {
 84                 dp[i][j][k][2] = dp[i][m-k+1][m-j+1][1];
 85             }
 86         }
 87     }
 88     for (int i = 1; i<=n; i++) {
 89         memset( last , 0 , sizeof(last) );
 90         for (int L = m; L>=1; L--){
 91             for (int j = 1; j+L-1<=m; j++){
 92                 int k = j+L-1;
 93                 if ( j == 1 || k == m ) continue;
 94                 dp[i][j][k][3] = dp[i][j][k+1][3];
 95                 last[k] += dp[i-1][j-1][k+1][0];
 96                 last[k] %= MOD;
 97                 last[k] += dp[i-1][j][k+1][1];
 98                 last[k] %= MOD;
 99                 last[k] += dp[i-1][j-1][k][2];
100                 last[k] %= MOD;
101                 last[k] += dp[i-1][j][k][3];
102                 last[k] %= MOD;
103                 dp[i][j][k][3] += last[k];
104                 dp[i][j][k][3] %= MOD;
105             }
106         }
107     }
108     for (int i = 1; i<=n; i++)
109         for (int j = 1; j<=m; j++)
110             for (int k = j; k<=m; k++)
111                 for (int c = 0; c<4; c++){
112                     ans += dp[i][j][k][c];
113                     ans %= MOD;
114                 }
115     printf("%d\n" , ans );
116     return 0;
117 }

 

转载于:https://www.cnblogs.com/lzqxh/archive/2013/02/21/2921043.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值