ZOJ - 3538 Arrange the Schedule

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天,m个操作,  下面m行, 第一个数字是代表第几天, 然后第二个字母是哪个人出题,  一共ABCD4个人, 问有多少种方式

A C 的话 中间能填B或D 所以两种,  第二个样例 先D 后面能接 ABC  不能连续两天同一个人出题

根据递推式构造出矩阵(3,2) (0,1)

(3,2)

公式:l[i]=3*r[i-1];   l[1]=3;            r[i]=l[i-1]+2*r[i-1];  r[1]=2;

#include <vector>
#include <iostream>
#include <string>
#include <map>
#include <stack>
#include <cstring>
#include <queue>
#include <list>
#include <cstdio>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <cctype>
#include <sstream>
#include <functional>
using namespace std;

#define pi acos(-1)
#define endl '\n'
#define me(x) memset(x,0,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,-1,-1,1,1};
const int dy[]={0,1,0,-1,1,-1,1,-1};
const int maxn=1e3+5;
const int maxx=5e4+100;
const double EPS=1e-7;
const int MOD=1000000007;
#define mod(x) ((x)%MOD);
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
//typedef tree<pt,null_type,less< pt >,rb_tree_tag,tree_order_statistics_node_update> rbtree;
/*lch[root] = build(L1,p-1,L2+1,L2+cnt);
    rch[root] = build(p+1,R1,L2+cnt+1,R2);中前*/
/*lch[root] = build(L1,p-1,L2,L2+cnt-1);
    rch[root] = build(p+1,R1,L2+cnt,R2-1);中后*/
long long gcd(long long a , long long b){if(b==0) return a;a%=b;return gcd(b,a);}

int n,m;
struct edge
{
    char op;
    int num;
}Q[20];
bool cmp(edge a,edge b)
{
    return a.num<b.num;
}

struct node
{
    LL t[2][2];
    void mex()
	{
		me(t);
	}
}a,b,unit;

node operator*(node a,node b)//重载运算符
{
    node ret;
    LL x;
    ret.mex();
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
    {
        x=0;
        for(int k=0;k<2;k++)
            x+=mod((LL)a.t[i][k]*b.t[k][j]);
        ret.t[i][j]=mod(x);
    }
    return ret;
}
void init()//矩阵的初始化
{
    for(int i=0;i<2;i++)
    {
        unit.t[i][i]=1;
    }
    return ;
}

node pow_mat(node a,LL n)//矩阵快速幂
{
    init();
    node ret=unit;
    while(n)
    {
        if(n%2)  ret=ret*a;
        a=a*a;
        n>>=1;
    }
    return ret;
}
LL quick_Mod(int m)//快速幂
{
	LL t=1;
	LL b=3;
	while(m)
	{
		if(m&1) t=mod(t*b);
		m>>=1;
		b=mod(b*b);
	}
	return t;
}
LL 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=pow_mat(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];
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        me(Q);
        for(int i=1;i<=m;i++)
        {
            scanf("%d %c",&Q[i].num,&Q[i].op);
        }
        sort(Q+1,Q+m+1,cmp);
        LL ans=1;
        if(m==0)
		{
			printf("%lld\n",(quick_Mod(n-1)*4)%MOD);
			continue;
		}
		ans=mod(ans*quick_Mod(Q[1].num-1));//把前面处理了
		ans=mod(ans*quick_Mod(n-Q[m].num));//把后面处理了
        for(int i=1;i<m;i++)
        {
            int cnt=Q[i+1].num-Q[i].num-1;
            if(Q[i+1].op==Q[i].op)
            {
                if(cnt==0)
                {
                    ans=0;
                    break;
                }
                else
                {
                    ans=mod(ans*(solve(cnt,1)));
                }
            }
            else
                ans=mod(ans*(solve(cnt,0)));
        }
        printf("%lld\n",ans);
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值