HDU-4655 Cut Pieces

题意:有N个格子能够被涂色,每个格子能够涂1-ai 种颜色,当N=6,涂色方案:112233 认为方案中共有3个颜色块;涂色方案:121212 认为方案中共有6个颜色块。所谓颜色块也就是整个涂色方案中相同连续的颜色被视作为一个颜色块。问如何安排 ai 的排列使得所有方案颜色块之和最大。

分析:从反面求解,首先能够产生的方案数一共有a1*a2*a3*...*an种,每种方案在没有相邻颜色认为为同一颜色块的情况下,颜色块的数量均为n。那么如何减掉重复计算的。可以考虑到任何一个k长连续颜色块,若统计其相邻格子颜色相同数量为k-1,如果减去这些相邻格子数正好满足同一颜色块只被统计一次。

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

typedef long long LL;
const int N = int(1e6)+5;
const int mod = int(1e9)+7;
int n, seq[N];
int f[N], t[N];

void solve() {
    int tot = 1, rep = 0;
    sort(seq, seq+n);
    f[0] = seq[0], t[n-1] = seq[n-1], t[n] = 1;
    for (int i = 1; i < n; ++i) {
        f[i] = (1LL*f[i-1]*seq[i]) % mod;
    }
    for (int i = n-2; i >= 0; --i) {
        t[i] = (1LL*t[i+1]*seq[i]) % mod;    
    }
    for (int i = 0; i < n; ++i) {
        tot = (1LL*tot*seq[i]) % mod; 
    }
    for (int i = n-1; i > n/2; --i) {
        rep = (rep + 2LL*f[i-1]*t[i+1]) % mod;
    }
    if (!(n&1)) rep = (rep + 1LL*f[n/2-1]*t[n/2+1]) % mod;
    printf("%d\n", ((1LL*tot*n-rep)%mod+mod)%mod);
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        for (int i = 0; i < n; ++i) {
            scanf("%d", &seq[i]);
        }
        solve();
    }
    return 0;    
}
View Code

相关文章: