HDU

来源:互联网 发布:网络维护是什么职位 编辑:程序博客网 时间:2024/06/08 16:44

Queuing

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5973    Accepted Submission(s): 2601


Problem Description
Queues and Priority Queues are data structures which are known to most computer scientists. The Queue occurs often in our daily life. There are many people lined up at the lunch time. 

  Now we define that ‘f’ is short for female and ‘m’ is short for male. If the queue’s length is L, then there are 2L numbers of queues. For example, if L = 2, then they are ff, mm, fm, mf . If there exists a subqueue as fmf or fff, we call it O-queue else it is a E-queue.
Your task is to calculate the number of E-queues mod M with length L by writing a program.
 

Input
Input a length L (0 <= L <= 10 6) and M.
 

Output
Output K mod M(1 <= M <= 30) where K is the number of E-queues with length L.
 

Sample Input
3 84 74 8
 

Sample Output
621
 

Author
WhereIsHeroFrom
 

Source
HDU 1st “Vegetable-Birds Cup” Programming Open Contest 
 

题意:有n个人排成一队,分男女,一共有2^n种情况,其中含有101或111的队列称为O-queue,其他称为E-queue

可以模拟出来,每一个位置放的是0还是1,然后进行一个一个的放,然后记录该位置所能得到的O-queue个数,就是递推的关系,因为一个队列前半部分不含有101或111不能说明它是E-queue,但是含有101或111就可以说明是O-queue了,所以我们记录O-queue的个数。

我们可以记录放的位置前面两个的数字类型所含有的个数(非O-queue),一共只有 00,01,10,11 四种。开一个二位数组a[3][3]就行了,当队列总数小于3时是不存在O-queue的,所以我们初始化a数组就是   a[0][0] =a[0][1] =a[1][0] =a[1][1] =1;然后从第三个位置开始放,只能放0和1,放0时不会得到O-queue,放1时只有10和11两种可以得到O-queue,然后ans[x]记录长度为x的队列含有O-queue的个数,ans[x] = a[1][0] + a[1][1] + ans[x-1]*2;更新a数组,就是后推了,然后在x之前已经是O-queue的都不会算在a数组中,因为已经是O-queue的队列不管后面是什么都是O-queue所以后面可以放1和2两种,所以就乘二。

有一些要注意的,因为内存的关系,所以不能把M为1-30的所有都存起来,所以我们先求1-30所有数的最小公倍数,这样除模的答案就不会一样,空间也可以大大的节省,不过要注意的是最小公倍数比较大,不能用快速幂来求,不然会爆long long,所以就直接存2^1000000就行了。

具体还是看代码

#include<iostream>#include<stdio.h>#include<string.h>using namespace std;#define LL long longLL gcd(LL a,LL b){    if(b==0)        return a;    return gcd(b,a%b);}LL ans[1001000],a[3][3],A[1001000],L,M,mod = 1;//ans[i]存大小为i的队列的O-queue个数,a[0][0]/a[1][0]/a[0][1]/a[1][1]存前两个数字为00、10、01、11的非O-queue个数,A[i]存2^iint main(){    for(int i=2;i<=30;i++)        mod = mod*i/gcd(mod,i);//求1-30的最小公倍数    a[0][0] = a[0][1] = a[1][0] = a[1][1] = 1;    A[0] = 1,A[1] = 2 ,A[2] = 4;    memset(ans,0,sizeof ans);    for(int i=3;i<=1000000;i++)    {        A[i] = (A[i-1] * 2)%mod;//求2^i        ans[i] += a[1][1] + a[1][0] + ans[i-1]*2;        LL a11 = a[1][1],a01 = a[0][1];        a[1][1] = a[0][1] % mod;        a[0][1] = a[0][0] % mod;        a[0][0] = (a[0][0] + a[1][0]) % mod;        a[1][0] = (a11 + a01) % mod;        ans[i] %= mod;    }    while(scanf("%lld%lld",&L,&M)!=EOF)        printf("%lld\n",(A[L]-ans[L]+mod)%M);    return 0;}