zoukankan      html  css  js  c++  java
  • 【纪中模拟2018.11.02】【JZOJ5945】昆特牌

    题目链接:https://jzoj.net/senior/#main/show/5945

    Limits

    TL: 1e3ms  ML:512Mb

    Description

      原本昆特牌中有$k$种卡牌和$n$种阵营,且每个阵营拥有的卡牌种数都是相等的。由于故障,卡牌数据被打乱了,每个阵营现在有$a_{i}$种卡牌。因为昆特牌即将迎来重大更新,每种牌的所属阵营并不重要,工程师只想尽快让每个阵营拥有相同数量的卡牌。由于数据库的结构原因,你每单位时间只能将一种牌向左边或右边相邻的一个阵营移动。问:最终的卡牌分布有多少种方案。两种方案不同当且仅当存在一种卡牌,它在两种方案中所属阵营不同。对$998244353$取模。

    Input  

    第一行一个整数$T$,表示数据组数。接下来每组数据,第一行一个整数$n$,第二行$n$个数,第$i$个数为$a_{i}$ ,意义见题目描述

    Ouput

    $T$行,每行一个数表示答案。

    Sample Input 1

    3

    3

    2 1 3

    3

    1 2 3

    3

    3 2 1

    Sample Ouput 1

    3

    9

    9

    Sample Explanation 1

    对于该组数据,初始为${{1,2}{3}{4,5,6}}$,移动结束后为${{1,2}{3,4}{5,6}}$$,$${{1,2}{3,6}{4,5}}$$,$${{1,2}{3,5}{4,6}}$

    Sample Input 2

    4
    3
    8 1 0
    4
    5 0 1 2
    4
    0 4 0 0
    4
    1 1 6 0

    Sample Ouput 2

    1120
    30
    24
    270

    Data Constraint

    保证输入合法,$nmid{}k,sum_{i=1}^{n}a_i=k$

    数据点 $kle$ $nle$ $Tle$
    1,2 10 5 10
    3,4 1000 100 10
    5,6 4000 10 10
    7~10 1000000 1000 500

     Solution

      考场上,笔者分析题面,回忆起经典贪心例题均分纸牌,认为此题同样可以线性贪心转移求解。

      读入牌堆数$n$、牌堆状态$a$。设最终各牌堆卡牌数为$ave$,则设差序列$b, forall{}iin{}[1,n],b_{i}=a_{i}-ave$

      规定操作方向为下界至上界,每次操作$i$牌堆后清零$b_{i}$。

      考虑$b_{i}>0$时,将$i$牌堆中所有超出$ave$的牌移至$i+1$牌堆,方案数为$lgroup^{a_{i}}_{b_{i}} group$。

      若$b_{i}<0$,则将$i+1$牌堆中取出$-b_{i}$张牌,移至$i$牌堆。此时若$i+1$牌堆足够多,方案数为$C_{a_{i+1}}^{-b_{i}}$;若$i+1$牌堆不够多,考虑实际移动牌的过程中,为了一遍转移,一定会先将$i+1$牌堆补成刚刚好足够补充$i$牌堆的状态,再将$i$牌堆补齐,同时$a_{i+1}$变为$ave$,方案数为$C_{ave-b_{i}}^{-b_{i}}$。实现过程中,将计算方案的$C$下标取$max$即可。

      核心思想如上。观察数据范围,$kle{}4e3$时,可以用杨辉三角预处理组合数,时间复杂度$O(k^2+T*n)$;$kle{}1e6$时,预处理阶乘及其乘法逆元,时间复杂度$O(k+T*n)$

    Code

     

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<ctime>
      6 using namespace std;
      7     typedef long long LL;
      8 bool isnum(char ch){
      9     if('0'<=ch&&ch<='9')
     10         return 1;
     11     return 0;
     12 }
     13     char ch;
     14     bool sign;
     15 void read(int& x){
     16     sign=0;
     17     for(ch=getchar();!isnum(ch);ch=getchar())
     18         if(ch=='-')
     19             sign=1;
     20     x=ch-'0';
     21     for(ch=getchar();isnum(ch);ch=getchar())
     22         x=(x<<3)+(x<<1)+ch-'0';
     23     if(sign)
     24         x=-x;
     25 }
     26 void read(LL& x){
     27     sign=0;
     28     for(ch=getchar();!isnum(ch);ch=getchar())
     29         if(ch=='-')
     30             sign=1;
     31     x=ch-'0';
     32     for(ch=getchar();isnum(ch);ch=getchar())
     33         x=(x<<3)+(x<<1)+ch-'0';
     34     if(sign)
     35         x=-x;
     36 }
     37     char stk[23];
     38     int cnt;
     39 void write(LL x){
     40     if(x==0){
     41         putchar('0');
     42         return ;
     43     }
     44     if(x<0){
     45         putchar('-');
     46         x=-x;
     47     }
     48     cnt=0;
     49     while(x){
     50         stk[++cnt]=x%10+'0';
     51         x/=10;
     52     }
     53     int i;
     54     for(i=cnt;i>=1;i--)
     55         putchar(stk[i]);
     56 }
     57     int T,n;
     58     LL a[1003];
     59     LL b[1003];
     60     const LL mod=998244353;
     61     LL jc[1000003];
     62     LL jcr[1000003];
     63 LL qpow(LL a,LL b){
     64     a%=mod;
     65     LL ans=1;
     66     while(b){
     67         if(b&1)
     68             ans=(ans*a)%mod;
     69         a=(a*a)%mod;
     70         b>>=1;
     71     }
     72     return ans;
     73 }
     74     LL x,y,z;
     75 LL C(LL n,LL m){
     76     x=jc[n];
     77     y=(jcr[m]*jcr[n-m])%mod;
     78     z=(x*y)%mod;
     79     return z;
     80 }
     81     LL ans;
     82 LL max(LL x,LL y){
     83     if(x>y)
     84         return x;
     85     return y;
     86 }
     87 int main(){
     88     freopen("gwent.in","r",stdin);
     89     freopen("gwent.out","w",stdout);
     90     read(T);
     91     int i;
     92     jc[0]=jcr[0]=1;
     93     for(i=1;i<=1000000;i++)
     94         jc[i]=(jc[i-1]*i)%mod;
     95     jcr[1000000]=qpow(jc[1000000],mod-2);
     96     for(i=1000000;i>=2;i--)
     97         jcr[i-1]=(jcr[i]*i)%mod;
     98     LL sum,ave;
     99     while(T--){
    100         read(n);
    101         for(i=1;i<=n;i++)
    102             read(a[i]);
    103         sum=0;
    104         for(i=1;i<=n;i++)
    105             sum+=a[i];
    106         ave=sum/n;
    107         for(i=1;i<=n;i++)
    108             b[i]=a[i]-ave;
    109         ans=1;
    110         for(i=1;i<n;i++)
    111             if(b[i]>0){
    112                 ans=(ans*C(a[i],b[i]))%mod;
    113                 //leap i sends, ans*=C(a[i],b[i])
    114                 a[i+1]+=b[i];
    115                 b[i+1]+=b[i];                
    116                 a[i]-=b[i];
    117                 b[i]=0;//set leap i empty
    118             }
    119             else if(b[i]<0){
    120                 ans=(ans*C(max(ave-b[i],a[i+1]),-b[i]))%mod;
    121                 /*
    122                 leap i gets.
    123                 if(a[i+1]>ave)
    124                     straight from i+1, ans*=C(a[i],-b[i])
    125                 else 
    126                     borrow from farther, ans*=C(ave-b[i],-b[i])
    127                 */
    128                 a[i+1]+=b[i];
    129                 b[i+1]+=b[i];
    130                 a[i]-=b[i];
    131                 b[i]=0;//set leap i empty
    132             }
    133         write(ans);
    134         putchar('
    ');//plural data, dont forget 
    
    135     }
    136     return 0;
    137 } 
    View Code

     

    Conclusion

      笔者能力不够,无法证明该贪心策略(极可能是错误的)。欢迎各位前来拍砖。

  • 相关阅读:
    ZOJ 3018
    poj2464
    Gauss
    【C】关于内存地址
    【C】typedef与define的区别
    C位移操作
    操作系统使用批处理文件更改网络配置
    【Linux】查看某个进程的线程数量(转)
    数据结构快速排序
    C++Explanation of ++val++ and ++*p++ in C
  • 原文地址:https://www.cnblogs.com/Hansue/p/9922907.html
Copyright © 2011-2022 走看看