比赛
题目
题意:
有N个blocks,每个block可以染的颜色为1~ai。连续的同颜色的blocks为一个piece,设N个blocks的某种上色方案的pieces数为s个。现在给你a序列,求将a重新排序后,所有上色方案的s的和的最大值是多少。
题解:
我的方法很麻烦……
首先取得最大值的a的排序方案可以是:如果a序列有序,则 新序列为 a1 an a2 an-1 ……YY出来的,用暴力验证过。
然后枚举所有区间(l,r),如果染同一颜色的话,上色方案有多少,那就是(l,r)的最小ai乘以不在(l,r)的所有aj。
但是这样会有重复,比如可能和r+1、l-1同色,所以要容斥,减去(l-1,r)和(l,r+1)还有加上(l-1,r+1).
那么可以看出,对于区间(l,r):
1、如果l!=r-1的话,算(l+1,r-1)时加一次,自己本身加一次,算(l+1,r)和(l,r-1)各减一次,刚好抵消,不加不减。
2、如果l=r-1的话,不存在(l+1,r-1),也就是总的来说要减一次。
3、如果l=r的话,只有加没有减。
预处理所有(1,l)和(r,n)的乘积,就可以O(n)算。
//Time:703ms //Memory:14428KB #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> using namespace std; #define MAXN 1000010 #define INF 1000000007 #define MOD 1000000007 #define MP(x,y) make_pair(x,y) long long pre[2][MAXN]; int num[MAXN],tnum[MAXN]; int cal(int n) { long long ans=1; sort(num,num+n); for(int i=0,j=0;i<n;i+=2,++j) tnum[i]=num[j]; for(int i=1,j=n-1;i<n;i+=2,--j) tnum[i]=num[j]; for(int i=0;i<n;++i) num[i]=tnum[i]; pre[0][0]=num[0]; for(int i=1;i<n;++i) pre[0][i]=pre[0][i-1]*num[i]%MOD; pre[1][n-1]=num[n-1]; for(int i=n-2;i>=0;--i) pre[1][i]=pre[1][i+1]*num[i]%MOD; for(int i=0;i<n;++i) ans=ans*num[i]%MOD; ans=ans*n%MOD; for(int i=0;i<n-1;++i) { int tmp=min(num[i],num[i+1]); long long tt; tt=(i?pre[0][i-1]:1)*(i<n-2?pre[1][i+2]:1); ans=(ans-tt%MOD*tmp%MOD+MOD)%MOD; } return ans; } int main() { //freopen("/home/moor/Code/input","r",stdin); int ncase,n; scanf("%d",&ncase); while(ncase--) { scanf("%d",&n); for(int i=0;i<n;++i) scanf("%d",&num[i]); printf("%d\n",cal(n)); } return 0; }