链接:http://acm.hdu.edu.cn/showproblem.php?pid=4655
题意:给你一组整数,代表每个木块所能涂成的颜色种数(编号1~ai),相邻的两块所能涂成的颜色如果是一样的认为是一块木块,问所有的涂色方案能涂成的木块总数。
思路:一开始赵鹏画的图上找到的思路。n*a1*a2*。。。。an代表的是不急相同颜色所能涂成的块数。但是假如说4 3 那么他们两块之间一定会有3种情况会涂成一个颜色即认为是一块,那么他们之间的总数为4*3-3。也就是说我们每一次产生的重复数会影响这个他所在的所有情况的个数,而每两个就会减少当前情况的一个,减少量为前面的所有情况*后面的所有情况*当前重复数。也就是说min(a[i],a[i-1])*pows/(a[i]*a[i-1])。这样吧所有重复情况计算一下就好了。 另外为了让减少的值最小,我们就要配上一个最小的a[i]和最大的a[i-1]。注意,x%mod/(y%mod) != x/y%mod.
代码:
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <stdlib.h> #include <vector> #include <queue> #include <stack> #define loop(s,i,n) for(i = s;i < n;i++) #define cl(a,b) memset(a,b,sizeof(a)) #define ll __int64 using namespace std; ll a[1000060]; ll b[1000060]; ll c[1000060]; ll powe[1000060]; ll pows[1000060]; const int mod = 1000000000+7; ll sum; int cmp1(const ll a,const ll b) { return a < b; } int cmp2(const ll a,const ll b) { return a > b; } int main() { //freopen("1001.txt","r",stdin); //freopen("out.txt","w",stdout); int t; scanf("%d",&t); while(t--) { int n,i; scanf("%d",&n); for(i = 1;i <= n;i++) { scanf("%I64d",&a[i]); b[i] = a[i]; } sort(a+1,a+n+1,cmp1); sort(b+1,b+n+1,cmp2); int ct1,ct2,ct; ct1 = ct2 = ct = 1; while(ct <= n ) { if(ct%2) { c[ct] = a[ct1]; ct++; ct1++; } else { c[ct] = b[ct2]; ct++; ct2++; } } if(n == 1){ printf("%d ",a[1]); continue; } sum = 0; pows[0] = 1; powe[n] = c[n]; powe[n+1] = 1; for(i = 1;i <= n;i++) { pows[i] = (pows[i-1]*c[i])%mod; powe[n-i] = powe[n-i+1]*c[n-i]%mod; } //pows = pows*n%mod; for(i = 2;i <= n;i++) { ll temp; sum = ((min(c[i],c[i-1])*pows[i-2]%mod)*powe[i+1]%mod+sum)%mod; } pows[n] = ((n*pows[n]%mod-sum)%mod+mod)%mod; printf("%I64d",pows[n]); puts(""); } return 0; }