• 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
    ",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
    ",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 }
  • 相关阅读:
    html 上传图片前预览
    php获取当月天数及当月第一天及最后一天、上月第一天及最后一天实现方法
    php 计算 pdf文件页数
    php 获取半年内每个月的订单数量, 总价, 月份
    php 获取两个数组之间不同的值
    小程序支付功能
    关于nginx的Job for nginx.service failed because the control process exited with error code.错误
    linux 安装 Apollo
    MongoDB待续。。。
    ABP vNext...待续
  • 原文地址:https://www.cnblogs.com/qzqzgfy/p/5596123.html
Copyright © 2020-2023  润新知