AtCoder Grand Contest #026 D - Histogram Coloring

Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 11001100 points

Problem Statement

Let us consider a grid of squares with 109109 rows and NN columns. Let (i,j)(i,j) be the square at the ii-th column (1iN)(1≤i≤N) from the left and jj-th row (1j109)(1≤j≤109) from the bottom.

Snuke has cut out some part of the grid so that, for each i=1,2,...,Ni=1,2,...,N, the bottom-most hihi squares are remaining in the ii-th column from the left. Now, he will paint the remaining squares in red and blue. Find the number of the ways to paint the squares so that the following condition is satisfied:

  • Every remaining square is painted either red or blue.
  • For all 1iN11≤i≤N−1 and 1jmin(hi,hi+1)11≤j≤min(hi,hi+1)−1, there are exactly two squares painted red and two squares painted blue among the following four squares: (i,j),(i,j+1),(i+1,j)(i,j),(i,j+1),(i+1,j) and (i+1,j+1)(i+1,j+1).

Since the number of ways can be extremely large, print the count modulo 109+7109+7.

Constraints

  • 1N1001≤N≤100
  • 1hi1091≤hi≤109

Input

Input is given from Standard Input in the following format:

NN
h1h1 h2h2 ...... hNhN

Output

Print the number of the ways to paint the squares, modulo 109+7109+7.


Sample Input 1 Copy

Copy
9
2 3 5 4 1 2 4 2 1

Sample Output 1 Copy

Copy
12800

One of the ways to paint the squares is shown below:

  #
  ##  #
 ###  #
#### ###
#########

Sample Input 2 Copy

Copy
2
2 2

Sample Output 2 Copy

Copy
6

There are six ways to paint the squares, as follows:

## ## ## ## ## ##
## ## ## ## ## ##

Sample Input 3 Copy

Copy
5
2 1 2 1 2

Sample Output 3 Copy

Copy
256

Every way to paint the squares satisfies the condition.


Sample Input 4 Copy

Copy
9
27 18 28 18 28 45 90 45 23

Sample Output 4 Copy

Copy
844733013

Remember to print the number of ways modulo 109+7109+7.

 

按照题目的要求,四个字符组成的正方形区域内两种颜色要各占一半。
先看一个例子

2

3 3

图案为

##

##

##

方案有这么几种(两种字符代表两种颜色)

|*#|#*|#*|*#|*#|#*|*#|#*|** |##

|#*|*#|*#|*#|*#|#*|#*|#*|##|**

|*#|#*|*#|#*|*#|#*|#*|*#|** |##

一共十种方案

可以总结的规律是如果一列中的颜色没有连续相同的,比如第1,2,9,10种方案,那么在第一列确定的情况下,第二列还可以有两种方案,但是一旦有连续相同的了,比如第k和k+1颜色相同,那么在第二列的k和k+1(如果存在的话)颜色就是已经确定的了,这样其他位置的颜色也是确定的,所以只有一种方案。如此就可以分开来存储有连续相同的方案数,和交替颜色(无连续相同)的方案数。

用dp[i][0]存无连续相同的方案数。而dp[i][j]分两种情况。

由于每一列高度不尽相同,还有考虑各种情况。

对于每一列,求无连续相同颜色的方案,只是局限于其与前一列接触的部分,不接触的部分颜色可以随意设置,至于下一列是否会接触这一部分再又下一列去选择。

dp[i][j]呢,对于与前一列有接触的部分,dp[i][j]存 有连续相同的方案数,假如这一列比前一列高出d个,那么dp[i][j] = dp[i - 1][j] * 2 ^ d,对于高出的部分是很灵活的,不会受前一列的限制,可以随意变化,至于高出来这一块的dp[i][j]存无连续相同的方案数(有连续相同的方案 在底部接触部分已经记录过)。

由于高度可能很大,所以这里采用离散化,把所有的高度存到一个数组里,这样每个列对应一个高度的下标。由于一共有不多于100列,所有最多有100个不相同的高度,直接按照高度差来计算相关量即可。

先看c++代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int MOD = (int)1e9 + 7;

int n,m,h[101],hnum[101],dh[101];///h记录每一列高度 dh记录离散化后的各不相同的高度 hnum记录h对应dh中的位置,即第几高的高度
long long dp[101][101];///记录第i列第n块高度往上的方案数

int pow_(long long x,int y) {///快速幂求 x的y次方
    long long ans = 1;
    if(y > 0) {
        while(y) {
            if(y % 2)ans = ans * x % MOD;
            x = x * x % MOD;
            y /= 2;
        }
    }
    return ans;
}

int main() {
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++) {
        scanf("%d",&h[i]);
        dh[++ m] = h[i];///先把高度存到dh数组 下标从1开始,方便后面dp
    }
    sort(dh + 1,dh + m + 1);///dh数组排序
    m = unique(dh + 1,dh + m + 1) - dh - 1;///dh数组离散化去掉重复的高度 m是不相同的高度数
    for(int i = 1;i <= n;i ++) {
        hnum[i] = lower_bound(dh + 1,dh + m + 1,h[i]) - dh;///每一列高度在dh数组中对应的位置
    }
    dp[0][0]=1;///初始化 当第0列有1个无连续相同的方案
    for(int i = 1;i <= n;i ++) {///对每一列每个高度段进行更新 更新过程为从下往上
        (dp[i][0] += dp[i - 1][0] * 2 % MOD) %= MOD;///无连续相同方案  加上前i - 1列无连续相同方案数*2 因为可以是与前一列对应位置同色或者异色一共两种方案
        for(int j = hnum[i] + 1;j <= hnum[i - 1];j ++)///如果前一列比这一列高,高出的部分也存着接触部分无连续相同的方案 但是可能会重复加上上一步的方案数所以下面更新高出的部分时会避免
            (dp[i][0] += dp[i - 1][j] * 2 % MOD) %= MOD;
        int d = pow_(2,h[i] - h[i - 1]);///比前一列高出部分的涂色方案数,如果比前一列低 d就等于1
        for(int j = 1;j <= min(hnum[i - 1],hnum[i]);j ++) {
            dp[i][j] = dp[i - 1][j] * d % MOD;///有连续相同颜色的方案数 已经分析过接触部分的颜色一定是定下的 所以这一列接触部分有连续相同部分的方案数由高出部分的变化决定 即 乘上d
        }
        for(int j = hnum[i - 1] + 1;j <= hnum[i];j ++) {///更新比前一列高出的部分 j从上一列的高度加1的下标开始
            if(j > 1)(dp[i][j] = dp[i - 1][0] * (pow_(2,dh[j] - dh[j - 1]) - 1) % MOD * 2 % MOD * pow_(2,h[i] - dh[j]) % MOD) %= MOD;
            ///一般情况 前i - 1列无连续方案 * (第j块高度变化方案 -1表示去掉无连续相同方案) * 2 * 剩下几块高度的变化方案数
            else (dp[1][1] = dp[0][0] * (pow_(2,dh[1]) - 2) % MOD * pow_(2,h[i] - dh[1]) % MOD) %= MOD;
            ///第一列的第一块高度 记录随意变化方案数 -2表示除去dp[i][0]已经记录过的无连续相同方案 勿重复记录
        }
    }
    long long ans = 0;
    for(int i = 0;i <= hnum[n];i++)
        (ans += dp[n][i]) %= MOD;
    printf("%lld",ans);
    return 0;
}
View Code

 


# ## # ### # #### ### #########
对于样例一来说,最初dp[0][0] = 1;dh[] = {0,1,2,3,4,5},hnum[] = {0,2,3,5,4,1,2,4,2,1},然后一列一列来
第一列:dp[1][0] = dp[0][0] * 2 = 2,2个无连续相同方案,然后前一列高度为0,所以第一列比前一列高出两个高度块,dp[1][1] = 0,dp[1][2] = 2;
第二列:dp[2][0] = dp[1][0] * 2 = 4,dp[2][1] = dp[1][1] * 2 = 0,dp[2][2] = dp[1][2] * 2 = 4;比前一列高出3 - 2 = 1个高度块,dp[2][3] = 4;
第三列:dp[3][0] = dp[2][0] * 2 = 8,dp[3][1] = dp[2][1] * 4 = 0,dp[3][2] = dp[2][2] * 4 = 16,dp[3][3] = dp[2][3] * 4 = 16,比前一列高出两个高度块,dp[3][4] = dp[2][0] * 2 * 2 = 16,dp[3][5] = 8;
第四列:dp[4][0] = dp[3][0] * 2 + dp[3][5] * 2 = 32,dp[4][1] = 0,dp[4][2] = dp[3][2] = 16,dp[4][3] = 16,dp[4][4] = 16;
第五列:dp[5][0] = dp[4][0] * 2 + dp[4][2] * 2 + dp[4][3] * 2 + dp[4][4] * 2 = 160,dp[5][1] = 0;
第六列:dp[6][0] = dp[5][0] * 2 = 320,dp[6][1] = 0,dp[6][2] = dp[5][0] * 2 = 320;
第七列:dp[7][0] = dp[6][0] * 2 = 640,dp[7][1] = 0,dp[7][2] = dp[6][2] * 4 = 1280,dp[7][3] = dp[6][0] * 2 * 2 = 1280,dp[7][4] = dp[6][0] * 2 = 640;
第八列:dp[8][0] = dp[7][0] * 2 + dp[7][3] * 2 + dp[7][4] * 2 = 5120,dp[8][1] = 0,dp[8][2] = dp[7][2] = 1280;
第九列:dp[9][0] = dp[8][0] * 2 + dp[8][2] * 2 = 12800,dp[9][1] = 0;
答案:12800

转载于:https://www.cnblogs.com/8023spz/p/9406634.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AtCoder Practice Contest #B - インタラクティブ練習 (Interactive Sorting) 是一道比较有趣的题目。它是一道交互式的排序题目,需要你与一个神秘程序进行交互,以便将一串无序的数字序列排序。 具体来说,这个神秘程序会给你一个长度为 $N$ 的数字序列,然后你需要通过询问它两个数字的大小关系,来逐步确定这个序列的排序顺序。每次询问之后,神秘程序都会告诉你两个数字的大小关系,比如第一个数字比第二个数字小,或者第二个数字比第一个数字小。你需要根据这个信息,来调整这个数字序列的顺序,然后再向神秘程序询问下一对数字的大小关系,以此类推,直到这个数字序列被完全排序为止。 在这个过程中,你需要注意以下几点: 1. 你最多只能向神秘程序询问 $Q$ 次。如果超过了这个次数,那么你的程序会被判定为错误。 2. 在每次询问之后,你需要及时更新数字序列的顺序。具体来说,如果神秘程序告诉你第 $i$ 个数字比第 $j$ 个数字小,那么你需要将这两个数字交换位置,以确保数字序列的顺序是正确的。如果你没有及时更新数字序列的顺序,那么你的程序也会被判定为错误。 3. 在询问的过程中,你需要注意避免重复询问。具体来说,如果你已经询问过第 $i$ 个数字和第 $j$ 个数字的大小关系了,那么你就不需要再次询问第 $j$ 个数字和第 $i$ 个数字的大小关系,因为它们的大小关系已经被确定了。 4. 在排序完成之后,你需要将排序结果按照从小到大的顺序输出。如果你输出的结果不正确,那么你的程序也会被判定为错误。 总的来说,这道题目需要你熟练掌握交互式程序设计的技巧,以及排序算法的实现方法。如果你能够熟练掌握这些技巧,那么就可以顺利地完成这道非传统题了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值