您的位置:首页 > 其它

BZOJ(本校) 3048 染色 - dp&递推找规律

2016-03-07 17:43 288 查看
【问题描述】

最近大大很happy,她制作了一些小旗,小旗都排成一列。现在她有四种颜色,分别为R,B,W,Y。突发奇想的大大决定出个问题考考你。她想知道,n面小旗染色有多少种不同的方案数。这样太简单了,答案不就是4^n么。于是她加了点限制,有5个限制条件,分别要求

1、相邻两面旗染色不相同

2、R,B两种颜色不能相邻

3、Y,W两种颜色不能相邻

4、R,W,B不能在一起。即不能出现连续三个是RWB的排列。

5、正反一样的算一种

但是大大觉得这样还是太简单了,于是她定义f(n)为n面红旗的方案数,她给你L和R两个正整数,让你计算∑Ri=Lf(i)\sum_{i=L}^{R}{f(i)},但是由于答案太大,你只需要mod 1000000007即可。

求答案。

【输入格式】

共一行两个正整数L和R,保证L<=R。

【输出格式】

输出只有一行,一个整数。

【样例输入输出1】

3 4

///

23

对于样例一的解释:

3面小旗:BWB, BYB, BYR, RWR, RYR, WBW, WBY, WRW, WRY, YBY, YRY (11 种)。

4面小旗: BWBW, BWBY, BYBW, BYBY, BYRW, BYRY, RWRW, RWRY, RYBW, RYBY, RYRW, RYRY (12 种)。

所以答案为11+12=23种。

【样例输入输出2】

5 6

///

64

【数据范围】

对于10%的数据,有1<=L<=R<=10

另有40%的数据,有 R-L+1<=10

对于100%的数据,1<=L<=R <=1000000000

分析:

先写个满足1-4条件的dp,如果长度为偶数,一定满足条件5(相邻两个不能相等),f(len)=dp(len)/2;如果长度为奇数,f(len)=(dp(len)-dp(len/2+1))/2+dp(len/2+1) ,因为本身回文的只出现了一次,所以要再加上本身回文的。

将dp值打个表,发现单从奇数位置或偶数位置看,竟然是等比数列!

那么耐着性子用等比求和公式推一推就出来了,具体看程序吧。

#include<cstdio>
#include<algorithm>
using namespace std;
#define Mod 1000000007

int phi;
void exgcd(int a,int b,int &d,int &x,int &y)
{
if(!b){
d=a;
x=1,y=0;
return ;
}
exgcd(b,a%b,d,y,x);
y=1LL*y-(a/b)*x;
}
int Inv(int a,int b)
{
int d,x,y;
exgcd(a,b,d,x,y);
return (1LL*x%Mod+Mod)%Mod;
}
int mypow(int x,int k)
{
int ret=1;
x%=Mod;
while(k){
if(k&1)
ret=1LL*ret*x%Mod;
x=1LL*x*x%Mod;
k>>=1;
}
return ret;
}
int sigma_pw(int q)
{
int r=mypow(3,q+1)%Mod;
return ((1LL*r-1+Mod)%Mod*phi)%Mod;
}
int Line(int t)
{
int p=t,q=t-1;
if(t%2) swap(p,q);
return (1LL*8*(sigma_pw(p/2-1)%Mod)%Mod+1LL*14*(sigma_pw(q/2-1)%Mod)%Mod)%Mod;
}
int Getans(int n)
{
if(n==0) return 0;
if(n==1) return 4;
int p1=Line(n)%Mod,p2=Line(n%2==0?n/2:(n/2+1))%Mod;
return ((((1LL*(p1-p2)%Mod+Mod)%Mod*phi)%Mod+p2)%Mod+(n>=1?1:0)*4)%Mod;
}
int main()
{
int L,R;
scanf("%d%d",&L,&R);
phi=Inv(2,Mod)%Mod;
int p=Getans(R),q=Getans(L-1);
printf("%d\n",(int)((1LL*(p-q)%Mod+Mod)%Mod));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: