码迷,mamicode.com
首页 > 其他好文 > 详细

zoj 3538 Arrange the Schedule

时间:2014-05-26 04:05:08      阅读:335      评论:0      收藏:0      [点我收藏+]

标签:des   style   class   blog   c   code   

Arrange the Schedule

Time Limit: 1 Second      Memory Limit: 65536 KB

In Summer 2011, the ZJU-ICPC Team has a n-days training schedule. ZJU-ICPC Team has been divided into 4 Group: Akiba, BiliBili, CIA, Double(Group A, B, C, D). There is a group in charge of the training problems on each day. As the ICPC Team manager, you have to decide which team is in charge of the problems on each day. But there are something you should rememeber:

1. No team is able to provide problems on two adjacent days
2. There are m days in the Summer 2011 that which group is in charge of the problems have been decided. (e.g. Akiba provides problems on day 1, BiliBili provides problems on day 6. And these can not be changed)

How many ways are there to arrange the schedule? Output the answer modulo 1000000007.

Input

There are multiple test cases(less than 50). Each case contains two integers n, m (1 ≤ n ≤ 10000000, 0 ≤ m ≤ 10), which indicate the number of days in Summer 2011 and the number of days that have been decided. 
Following m lines. Each line contains one integer ai and one upper letter Ch (‘A‘ ≤ Ch ≤ ‘D‘), indicate that on day ai (1 ≤ ai ≤ n), group Ch is in charge of the problems. We guarantee that all ai are distinct. There is a blank line after each input case.

Output

For each case, output a single line containing the answer, the number of the ways to arrange the schedule modulo 1000000007.

Sample Input

3 2
1 A
3 C

2 1
1 D

Sample Output

2
3

Hint

Case 1:
2 ways: ABC, ADC.
Case 2:
3 ways: DA, DB, DC.

题解:
         大致的意思就是说给定n天,每天从A,B,C,D里面挑一个字母放进去,使得相邻的字母不相同,题目规定给定特定的m天,这m天的字母已经给定,并且不能修改,问不同的放置方法。
        首先想到的就是推公式,那么我来讲一下我的思路:
        首先假设n=3,m=2(d=n-m=1),那么规定为第一天为A,第三天为A;
        1.就是这个样子    A__A ,那么第二天  的 填冲方法就是三种 B,C,D;-------用l[d=1]来代表,那么l[1]=3;
        2.那么假设  第三天是 B,也就是 A__B  ,那么 第二天的填充方法就是两种 C,D;-------用r[d=1]来代表,那么r[1]=2;
        上面的例子中1代表的是相邻的规定的两个字母是相同的情况(A=A),而2代表的是不同的情况(A!=B)。
 
        然后假设n=4,m=2(d=n-m=2),那么规定为第一天为A,第四天为A;
        就是这个样子    A____A ,那么第二天  的 填冲方法就是三种 B,C,D,那么第三天呢?此时,先来看一下,第二天的三种情况B,C,D,与第四天均是不相同的,那么这时就可以从d=2的情况转化到d=1的2的情况(也就是A!=B的情况);---------l[d=2]=3*r[1];
        那么假设  第四天是 B,也就是 A____B  ,那么 第二天的填充方法就是两种B,C,D,那么第三天呢?此时,先来看一下,假设第二天是B,那么就转化成d=1的1的情况,假设第二天是C,D,那么就转化成d=1的2的情况;---------r[d=2]=l[1]+2*r[1];
 
       ----------
       -------
       这样以此类推.....
       这样就能总结出公式:l[i]=3*r[i-1];   l[1]=3;
                                           r[i]=l[i-1]+2*r[i-1];  r[1]=2;
       如果会母函数的话,那么可以推倒一下计算公式。这里不介绍推导公式的做法了,下面介绍的是矩阵快速幂的做法。
       由于题目中的n是10^7的,所以使用两个数组打表记录的话会爆内存,所以用矩阵快速幂来计算还是比较合适的。
       够造a矩阵| 3  2 |      b矩阵 | 0  1 |
                                                  | 3  2 |
       那么只需要计算 b矩阵的 幂就可以了啊。
注意:当给定的某两天相邻且字母相同时,输出0。
           区间两侧的情况和m=0的情况单独处理。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define p 1000000007
using namespace std;

struct mat
{
    long long t[2][2];
    void set()
    {
        memset(t,0,sizeof(t));
    }
} a,b;

mat multiple(mat a,mat b)
{
    int i,j,k;
    mat temp;
    temp.set();
    for(i=0; i<2; i++)
        for(j=0; j<2; j++)
        {
                for(k=0; k<2; k++)
                    temp.t[i][j]=(temp.t[i][j]+a.t[i][k]*b.t[k][j])%p;
        }
    return temp;
}

mat quick_mod(mat b,int m)
{
    mat t;
    t.set();
    for(int i=0; i<2; i++) t.t[i][i]=1;
    while(m)
    {
        if(m&1)
        {
            t=multiple(t,b);
        }
        m>>=1;
        b=multiple(b,b);
    }
    return t;
}

long long quick_Mod(int m)
{
    long long t=1;
    long long b=3;
    while(m)
    {
        if(m&1) t=t*b%p;
        m>>=1;
        b=b*b%p;
    }
    return t;
}

long long solve(int m,int c)
{
    if(m<=0) return 1;
    b.t[0][0]=0;
    b.t[0][1]=1;
    b.t[1][0]=3;
    b.t[1][1]=2;
    a=quick_mod(b,m-1);
    if(c==1) return 3*a.t[0][0]+2*a.t[1][0];
    return 3*a.t[0][1]+2*a.t[1][1];
}
struct node
{
    int q;
    char s[3];
}t[12];
bool cmp(node a,node b)
{
    return a.q<b.q;
}
int main()
{
    int n,m;

    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int sum1=0,sum2=0;
        long long ans=1;
        if(m==0)
        {
            printf("%lld\n",quick_Mod(n-1)*4%p);
            continue;
        }
        for(int i=0;i<m;i++)
        {
            scanf("%d%s",&t[i].q,t[i].s);
        }
        sort(t,t+m,cmp);
        ans=ans*quick_Mod(t[0].q-1)%p;
        ans=ans*quick_Mod(n-t[m-1].q)%p;
        for(int i=0;i<m-1;i++)
        {
            if(t[i].s[0]==t[i+1].s[0])
            {
               sum1=t[i+1].q-t[i].q-1;
               if(sum1==0)
               {
                   ans=0;
                   break;
               }
               else
                ans=ans*solve(sum1,1)%p;
            }

            else sum2=t[i+1].q-t[i].q-1,ans=ans*solve(sum2,0)%p;
        }
        printf("%lld\n",ans);
    }
    return 0;
}


zoj 3538 Arrange the Schedule,布布扣,bubuko.com

zoj 3538 Arrange the Schedule

标签:des   style   class   blog   c   code   

原文地址:http://blog.csdn.net/knight_kaka/article/details/26744611

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!