NOI十连测 第三测 T1

 

 

 这么二逼的题考试的时候我想了好久,我真是太弱了。。。

 首先,由于ans都乘上了i*(i-1)/2,实际上要求的就是每个数的所有可能出现次数*这个数的权值。

我们发现,每个数的本质是一样的,我们记一个sum为数的总和,这样只要统计一次就OK了。

我们把每次的选择抽象成有向边,每个状态视为点,这样就构成一个有根树。

 如图

我们只考虑1对答案的贡献。如图,在每层计算当前合并对答案的贡献,也就是要能得知我在这个节点选择合并1或者1的联通块,那么我能覆盖到几个叶子节点?

那么就变成O(n)的组合数学题了。。对了,组合数用到的阶乘和阶乘逆元可以O(n)预处理。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 #define ll long long
  7 int ans=0,a[200005],n,cnt[20],size[20];
  8 const ll Mod=1000000007;
  9 ll sum,jcny[200005],jc[200005],f[200005],son[200005],Num[200005];
 10 int read(){
 11     int t=0,f=1;char ch=getchar();
 12     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
 13     while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
 14     return t*f;
 15 }
 16 bool cmp(const int &a,const int &b){
 17     return a>b;
 18 }
 19 ll gcd(ll a,ll b){
 20     if (b==0) return a;
 21     else return gcd(b,a%b);
 22 }
 23 void exgcd(ll a,ll b,ll &x,ll &y){
 24     if (b==0){
 25         x=1;y=0;
 26         return;
 27     }
 28     exgcd(b,a%b,x,y);
 29     ll t=x;
 30     x=y;
 31     y=t-(a/b)*y;
 32 }
 33 void init(){
 34     jc[0]=1;jcny[0]=1;
 35     for (ll i=1;i<=n+1;i++) jc[i]=(jc[i-1]*i)%Mod;
 36     ll x,y;
 37     exgcd(jc[n+1],Mod,x,y);
 38     jcny[n+1]=(x%Mod+Mod)%Mod;
 39     for (int i=n;i>=1;i--) jcny[i]=(jcny[i+1]*(i+1))%Mod;
 40 }
 41 ll C(int n,int m){
 42     return (((jc[n]*jcny[m])%Mod)*jcny[n-m])%Mod;
 43 }
 44 int dfs(int x1,int x2,int x3,int x4,int x5,int num,int res){
 45     int b[5];
 46     int Res=1;
 47     if (num==1){
 48         ans=(ans+res)%Mod;
 49         return Res;
 50     }
 51     b[0]=x1;b[1]=x2;b[2]=x3;b[3]=x4;b[4]=x5;
 52     std::sort(b,b+num,cmp);
 53     for (int i=0;i<num;i++)
 54      for (int j=i+1;j<num;j++){
 55             b[i]+=b[j];int tmp=b[j];b[j]=0;std::swap(b[j],b[num-1]);
 56             Res+=dfs(b[0],b[1],b[2],b[3],b[4],num-1,(res+b[i])%Mod);
 57             std::swap(b[j],b[num-1]);
 58             b[i]-=tmp;b[j]=tmp;
 59     }
 60     return Res;  
 61 }
 62 ll inv(ll a){
 63     ll x,y;
 64     exgcd(a,Mod,x,y);
 65     return x;
 66 }
 67 void sbpianfen(){
 68     int k=dfs(a[1],a[2],a[3],a[4],a[5],n,0);
 69     printf("%d\n",ans); 
 70 }
 71 ll A(int n,int m){
 72     return (jc[n]*jcny[n-m])%Mod;
 73 }
 74 ll Pow(ll x,ll y){
 75     ll res=1;
 76     while (y){
 77         if (y%2) res=(res*x)%Mod;
 78         x=(x*x)%Mod;
 79         y/=2;
 80     }
 81     return res;
 82 }
 83 void sxpianfen(){
 84     ll res=0;
 85     son[1]=1;son[0]=1;
 86     for (int i=2,num=n;i<=n;i++,num--)
 87      son[i]=(son[i-1]*C(num,2))%Mod;//这行
 88     Num[n-1]=1;Num[n]=1;Num[n+1]=1;Num[n+2]=1;
 89     for (int i=n-2,num=2;i>=1;i--,num++)
 90       Num[i]=(Num[i+1]*C(num+1,2))%Mod;  //叶子
 91     for (int i=1,num=n;i<=n-1;i++,num--){
 92         res=(res+(son[i]*Num[i+1])%Mod*(num-1))%Mod;
 93     }
 94     res=(res*sum)%Mod;
 95     printf("%lld\n",res);
 96 }
 97 int main(){
 98     n=read();init();
 99     for (int i=1;i<=n;i++)
100      a[i]=read(),sum=(sum+a[i])%Mod;
101     if (n<=5){sbpianfen();return 0;}
102     if (n<=100000){sxpianfen();return 0;}
103 }

 

posted @ 2016-06-18 19:13  GFY  阅读(337)  评论(0编辑  收藏  举报