题目描述
有一个长度为 nnn 的序列,xht37 现在想分块维护它。
PinkRabbit 要求他只准将序列分成 PRPRPR 种长度的块。
NaCly_Fish 要求他只准将序列分成 NFNFNF 种长度的块。
同一个人可能会要求 xht37 多次相同的块长。
xht37 想同时满足 PinkRabbit 和 NaCly_Fish 要求,只好使用两个人都允许的长度分块。
xht37 想知道,有多少种不同的分块方案,答案对 109+710 ^ 9 + 7109+7 取模。
输入格式
第一行一个正整数 nnn,表示序列的长度。
第二行一个正整数 PRPRPR,表示 PinkRabbit 要求的分块长度的种类数。
第三行 PRPRPR 个正整数,表示 PinkRabbit 要求的 PRPRPR 种分块长度。
第四行一个正整数 NFNFNF,表示 NaCly_Fish 要求的分块长度的种类数。
第五行 NFNFNF 个正整数,表示 NaCly_Fish 要求的 NFNFNF 种分块长度。
输出格式
输出一行一个整数,表示不同分块方案的种类数对 109+710 ^ 9 + 7109+7 取模的值。
样例
输入 111
4
3
1 2 3
3
1 2 4
输出 111
5
样例 111 说明
PinkRabbit 和 NaCly_Fish 都允许的块长为 {1,2}\{1,2\}{1,2}。
长度为 444 的序列分块,每块长度为 {1,2}\{1,2\}{1,2} 的方案有:
- 1 1 1 11\ 1\ 1\ 11 1 1 1
- 1 1 21\ 1\ 21 1 2
- 1 2 11\ 2\ 11 2 1
- 2 1 12\ 1\ 12 1 1
- 2 22\ 22 2
共 555 种。
输入 222
19260817
7
8 9 6 3 7 2 1
7
4 5 2 9 7 8 3
输出 222
859254329
数据范围与提示
设最大块长为 xxx。
对于 60%60 \%60% 的数据,1≤n≤1061 \le n \le 10 ^ 61≤n≤106,1≤PR,NF,x≤101 \le PR,NF,x \le 101≤PR,NF,x≤10,保证同一个人不会要求多次相同的块长。
对于 100%100 \%100% 的数据,1≤n≤10181 \le n \le 10 ^ {18}1≤n≤1018,1≤PR,NF,x≤1001 \le PR,NF,x \le 1001≤PR,NF,x≤100。
矩阵快速幂
不是
保证同一个人不会要求多次相同的块长吗 WA了好多发
f5=f(5-2) +f(5-3)
矩阵快速幂构造矩阵方法 第一行就是 0 1 1 0 0
1 0 0 0 0
0 1 0 0 0
. .... .........
0 0 0 0 1
洛谷 760ms
xht37的OJ 1093ms卡常-----
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll mod=1e9+7;
ll flag[105];
ll num[105];
ll exi[105];
ll ma=100;
ll p[105][105];
ll tp2[105][105];
ll ans[105];
ll tp[105];
void f1()
{
for(ll i=1; i<=ma; i++)
{
tp[i]=0;
for(ll j=1; j<=ma; j++)
{
tp[i]=(tp[i]+p[i][j]*ans[j])%mod;
}
}
for(ll i=1; i<=ma; i++)
ans[i]=tp[i];
}
void f2()
{
for(ll i=1; i<=ma; i++)
{
for(ll j=1; j<=ma; j++)
{
tp2[i][j]=0;
for(ll k=1; k<=ma; k++)
{
tp2[i][j]=(tp2[i][j]+p[i][k]*p[k][j])%mod;
}
}
}
for(ll i=1; i<=ma; i++)
{
for(ll j=1; j<=ma; j++)
{
p[i][j]=tp2[i][j];
}
}
}
void print()
{
for(ll i=1; i<=ma; i++)
{
for(ll j=1; j<=ma; j++)
{
printf("%lld ",p[i][j]);
}
printf("\n");
}
printf("\n");
for(ll i=1;i<=ma;i++)
printf("%lld ",ans[i]);
printf("\n");
printf("\n");
}
ll flag2[105];
int main()
{
ll n;
ll cnt=0;
scanf("%lld",&n);
memset(p,0,sizeof(p));
memset(flag,0,sizeof(flag));
memset(flag2,0,sizeof(flag2));
memset(num,0,sizeof(num));
ll l1,l2,x;
scanf("%lld",&l1);
for(ll i=0; i<l1; i++)
{
scanf("%lld",&x);flag[x]=1;
}
scanf("%lld",&l2);
for(ll i=0; i<l2; i++)
{
scanf("%lld",&x);
flag2[x]=1;
}
for(ll i=0; i<105; i++)
if(flag[i]&&flag2[i])
num[cnt]=i,cnt++;
for(ll i=0; i<cnt; i++)
p[1][num[i]]=1;
for(ll i=2; i<=ma; i++)
{
p[i][i-1]=1;
}
memset(ans,0,sizeof(ans));
ans[1]=1;
while(n)
{
if(n&1)
f1();
//print();
f2();
n>>=1;
}
printf("%lld\n",ans[1]%mod);
}