• Mysterious For(hdu4373)


    Mysterious For

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 694    Accepted Submission(s): 264


    Problem Description
    MatRush is an ACMer from ZJUT, and he always love to create some special programs. Here we will talk about one of his recent inventions.

    This special program was called "Mysterious For", it was written in C++ language, and contain several simple for-loop instructions as many other programs. As an ACMer, you will often write some for-loop instructions like which is listed below when you are taking an ACM contest.
    for (int i = 0; i < n; i++) {
      for (int j = i; j < n; j++) {
        for (int k = j; k < n; k++) {
          blahblahblah();
        }
      }
    }

    Now, MatRush has designed m for-loop instructions in the "Mysterious For" program, and each for-loop variable was stored in an array a[], whose length is m.

    The variable i represents a for-loop instructions is the i-th instruction of the "Mysterious For" program.There only two type of for-loop instructions will occur in MatRush's "Mysterious For" program:

    1-type: if a for-loop belongs to 1-type, it will be an instruction like this:
    for (int a[i] = 0; a[i] < n; a[i]++) {
        ...
    }

    2-type: if a for-loop belongs to 2-type, it will be an instruction like this:
    for (int a[i] = a[i - 1]; a[i] < n; a[i]++) {
        ...
    }

    In addition, after the deepest for-loop instruction there will be a function called HopeYouCanACIt(), here is what's inside:
    void HopeYouCanACIt() {
        puts("Bazinga!");
    }

    So, the "Mysterious For" program, obviously, will only print some line of the saying: "Bazinga!", as it designed for.

    For example, we can assume that n equals to 3, and if the program has three 1-type for-loop instructions, then it will run 33=27 times of the function HopeYouCanACIt(), so you will get 27 "Bazinga!" in total. But if the program has one 1-type for-loop instruction followed by two 2-type for-loop instructions, then it will run 3+2+1+2+1+1=10 times of that function, so there will be 10 "Bazinga!" on the screen.

    Now MatRush has the loop length n and m loop instructions with certain type, then he want to know how many "Bazinga!" will appear on the screen, can you help him? The answer is too big sometimes, so you just only to tell him the answer mod his QQ number:364875103.

    All for-loop instructions are surely nested. Besides, MatRush guaranteed that the first one belongs to the 1-type. That is to say, you can make sure that this program is always valid and finite. There are at most 15 1-type for-loop instructions in each program.
     
    Input
    First, there is an integer T(T<=50), the number of test cases.
    For every case, there are 2 lines.
    The first line is two integer n(1<=n<=1000000) and m(1<=m<=100000) as described above.
    The second line first comes an integer k(1<=k<=15), represents the number of 1-type loop instructions, then follows k distinctive numbers, each number is the i-th 1-type loop instruction's index(started from 0), you can assume the first one of this k numbers is 0 and all numbers are ascending.
    All none 1-type loop instructions of these m one belongs to 2-type.
     
    Output
    For each certain "Mysterious For" program, output one line, "Case #T: ans", where T stands for the case number started with 1, and ans is the number of "Bazinga!" mod 364875103.
     
    Sample Input
    5 3 3 3 0 1 2 3 3 1 0 3 3 2 0 2 4 4 4 0 1 2 3 10 10 10 0 1 2 3 4 5 6 7 8 9
     
    Sample Output
    Case #1: 27 Case #2: 10 Case #3: 18 Case #4: 256 Case #5: 148372219
    Hint
    For the third program, the code is like this: for (int a[0] = 0; a[0] < n; a[0]++) { for (int a[1] = a[0]; a[1] < n; a[1]++) { for (int a[2] = 0; a[2] < n; a[2]++) { HopeYouCanACIt(); } } } Because n = 3, the answer is 3*3+2*3+1*3=18.
     题意:
    m个for循环嵌套,有两种形式,第一类从1开始到n,第二类从上一层循环当前数开始到n,第一层一定是第一种类型,问总的循环的次数对364875103取余的结果。
    思路:中国剩余定理+lucas定理;
    下面我转载一篇写得不错的思路的一部分
    {首先可以看出,每一个第一类循环都是一个新的开始,与前面的状态无关,所以可以把m个嵌套分为几个不同的部分,每一个部分由第一类循环开始,最终结果相乘就可以。
    剩下的就是第二类循环的问题,假设一个m层循环,最大到n,
    只有第一层:循环n次。C(n, 1)
    只有前两层:循环n + (n - 1) + ... + 1 = (n + 1) * n / 2 = C(n + 1, 2);}
    接下来是我自己的证明:
    有m层循环,然后每层n个;
    我们考虑最后一层,然后我们可以用dp的思想,最后一层的第一个数的次数为,C(m-1,m-1),第二个数可以接在上一层,以小于等于第二个结尾的数的后面,那么就是C(m,m-1),同理可以得到剩下的数被计数的个数为C(m+k-1,m-1);
    那么这个总的循环次数就是C(m-1,m-1)+C(m,m-1)+C(m+1,m-1)....+C(m+k-1,m-1)+...C(m+n-2,m-1)=
    C(m)(m)+C(m,m-1)+C(m+1,m-1)+....C(m+n-2,m-1)根据杨辉三角合并就可得到最终的答案为C(n+m-1,m);
    要完整的证明还要用数学归纳法;
    然后,我们发现mod不是素数,我们拆分成97*(mod/97);两个素数分别取模,然后用中国剩余定理求出对于mod的模数,同时组合数对97取模用lucas定理,对另一个比较大的直接费马小定理即可。
     
     
      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <cmath>
      5 #include <iostream>
      6 #include <algorithm>
      7 #include <map>
      8 #include <queue>
      9 #include <vector>
     10 using namespace std;
     11 typedef long long LL;
     12 bool flag[1000005];
     13 LL N1[1200005];
     14 LL N2[1200005];
     15 const LL mod1=97;
     16 const LL mod2=364875103/97;
     17 LL quick(LL n,LL m,LL p);
     18 LL lucas(LL n,LL m,LL p);
     19 pair<LL,LL> CHA(LL *a,LL n,LL *b);
     20 LL  a[10];
     21 LL b[10];
     22 int main(void)
     23 {
     24         LL i,j;
     25         int ca=0;
     26         int k;
     27         scanf("%d",&k);
     28         LL n,m;
     29         N1[0]=1;
     30         N2[0]=1;
     31         N2[1]=1;
     32         N1[1]=1;
     33         for(i=2; i<1200005; i++)
     34         {
     35                 N1[i]=(N1[i-1]*i)%mod1;
     36                 N2[i]=(N2[i-1]*i)%mod2;
     37         }
     38         while(k--)
     39         {
     40                 ca++;
     41                 scanf("%lld %lld",&n,&m);
     42                 LL s;
     43                 for(i=0; i<1000005; i++)
     44                         flag[i]=false;
     45                 scanf("%lld",&s);
     46                 LL t;
     47                 for(i=0; i<s; i++)
     48                 {
     49                         scanf("%lld",&t);
     50                         flag[t]=true;
     51                 }
     52                 LL ack=1;
     53                 LL  alk=1;
     54                 for(i=0; i<m;)
     55                 {
     56                         if(flag[i]&&(flag[i+1]&&i!=m-1||i==m-1))
     57                         {
     58                                 ack=ack*n%mod1;
     59                                 alk=alk*n%mod2;
     60 
     61                                 i++;
     62                         }
     63                         else
     64                         {
     65                                 for(j=i+1; j<m; j++)
     66                                 {
     67                                         if(flag[j])
     68                                                 break;
     69                                 }
     70                                 LL cc=j-i;
     71                                 i=j;
     72                                 LL x=N2[n+cc-1];
     73                                 LL y=N2[cc]*N2[n-1];
     74                                 x=x*quick(y,mod2-2,mod2)%mod2;
     75                                 LL ap=lucas(cc,n+cc-1,mod1);
     76                                 ack=ack%mod1*ap%mod1;
     77                                 alk=alk%mod2*(x)%mod2;
     78                         }
     79                 }
     80                 LL sum=mod1*mod2;
     81                 memset(a,0,sizeof(a));
     82                 memset(b,0,sizeof(b));
     83                 a[0]=mod1;
     84                 b[0]=ack;
     85                 b[1]=alk;
     86                 a[1]=mod2;
     87                 LL an=0;
     88                 pair<LL,LL>NA=CHA(a,2,b);
     89                 printf("Case #%d: %lld
    ",ca,NA.first%(mod1*mod2));
     90         }
     91         return 0;
     92 }
     93 pair<LL,LL> CHA(LL *a,LL n,LL *b)
     94 {
     95         int i,j;
     96         LL sum=1;
     97         LL answer=0;
     98         for(i=0; i<n; i++)
     99         {
    100                 sum*=a[i];
    101         }
    102         for(i=0; i<n; i++)
    103         {
    104                 LL t=sum/a[i];
    105                 LL ni=quick(t,a[i]-2,a[i]);
    106                 LL ask=ni*b[i]%sum;
    107                 ask=ask*t%sum;
    108                 answer+=ask;
    109                 answer%=sum;
    110         }
    111         return make_pair(answer,sum);
    112 }
    113 LL quick(LL n,LL m,LL p)
    114 {
    115         n%=p;
    116         LL ak=1;
    117         while(m)
    118         {
    119                 if(m&1)
    120                 {
    121                         ak=ak*n%p;
    122                 }
    123                 n=n*n%p;
    124                 m/=2;
    125         }
    126         return ak;
    127 }
    128 LL lucas(LL n,LL m,LL p)
    129 {
    130         if(n==0)
    131         {
    132                 return 1;
    133         }
    134         else
    135         {
    136                 LL nx=n%p;
    137                 LL ny=m%p;
    138                 if(nx>ny)
    139                 {
    140                         return 0;
    141                 }
    142                 else
    143                 {
    144                         LL x=N1[nx]*N1[ny-nx]%p;
    145                         LL y=quick(x,p-2,p)*N1[ny]%p;
    146                         return y*lucas(n/p,m/p,p)%p;
    147                 }
    148         }
    149 }
    油!油!you@
  • 相关阅读:
    解决面部毛孔粗大的7个小窍门 生活至上,美容至尚!
    几个物美价廉的养生食物 生活至上,美容至尚!
    瘦脸美食 冬瓜玉米汤 生活至上,美容至尚!
    橙子减肥法:好吃快速成为瘦美人 生活至上,美容至尚!
    实用的胖脸的瘦脸方法 生活至上,美容至尚!
    既省钱又快乐的减肥方式 生活至上,美容至尚!
    推荐一个单干网赚好站!BUXJOB 生活至上,美容至尚!
    祛除雀斑的健康方法 生活至上,美容至尚!
    祛痘收缩毛孔的简单方法 生活至上,美容至尚!
    六个动作帮你甩掉小肚腩 生活至上,美容至尚!
  • 原文地址:https://www.cnblogs.com/zzuli2sjy/p/5727708.html
Copyright © 2020-2023  润新知