有一個數軸。yww 最開始在位置 \(0\)。yww 總共要跳躍不少次。每次 yww 能夠往右跳 \(1\) 單位長度,或者跳到位置 \(1\)。數組
定義位置序列爲 yww 在每次跳躍以後所在的位置組成的序列(顯然不包括 \(0\))。dom
有 \(k\) 個數是好的,分別爲 \(a_1,a_2,\ldots,a_k\)。優化
定義一個位置序列是好的當且僅當:spa
定義兩個位置序列本質相同當且僅當:code
求全部本質不一樣的好的位置序列的長度之和。get
對 \({10}^9+7\) 取模。string
\(k\leq 100,n,m\leq {10}^9\)it
記 \(b_i=a_i-a_{i-1}\)。io
考慮對於一個最終位置是好的點的位置序列,求出和這個序列本質相同的序列中,最終能到達那些點。function
這樣就有一個 \(O(2^kn)\) 的DP了。
若是你把這個作法寫出來,就會發現其實只有 \(O(k)\) 個狀態是有用的。
這是爲何呢?
對於一個位置集合 \(S\),考慮集合內最大的元素 \(x\),對於一個更小的 \(y\),\(y\in S\) 當且僅當 \(b_1\leq b_{x-y+1}\) 且 \(b_{2\ldots y}=b_{x-y+2 \ldots x}\) 這樣對於每一個 \(x\),\(S\) 是惟一的。
直接套個矩陣快速冪優化DP就 \(O(k^3\log n)\) 了。
還能夠換一種方向思考。
考慮對於一個好的序列,每次取一個最短的前綴,知足後面仍是合法的好的序列。
若是一個前綴能被分紅幾個前綴拼在一塊兒,就不能取這個前綴了。
處理出刪掉 \(b_1\) 以後的 ex_kmp 數組就能夠快速求出每一個前綴是否可選。
這就是一個常係數齊次線性遞推。
直接BM+倍增取模能夠作到 \(O(k^2+k\log k\log n)\)
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<ctime> #include<functional> #include<cmath> #include<vector> #include<assert.h> #include<map> //using namespace std; using std::min; using std::max; using std::swap; using std::sort; using std::reverse; using std::random_shuffle; using std::lower_bound; using std::upper_bound; using std::unique; using std::vector; using std::map; typedef long long ll; typedef unsigned long long ull; typedef double db; typedef std::pair<int,int> pii; typedef std::pair<ll,ll> pll; void open(const char *s){ #ifndef ONLINE_JUDGE char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout); #endif } void open2(const char *s){ #ifdef DEBUG char str[100];sprintf(str,"%s.in",s);freopen(str,"r",stdin);sprintf(str,"%s.out",s);freopen(str,"w",stdout); #endif } int rd(){int s=0,c,b=0;while(((c=getchar())<'0'||c>'9')&&c!='-');if(c=='-'){c=getchar();b=1;}do{s=s*10+c-'0';}while((c=getchar())>='0'&&c<='9');return b?-s:s;} void put(int x){if(!x){putchar('0');return;}static int c[20];int t=0;while(x){c[++t]=x%10;x/=10;}while(t)putchar(c[t--]+'0');} int upmin(int &a,int b){if(b<a){a=b;return 1;}return 0;} int upmax(int &a,int b){if(b>a){a=b;return 1;}return 0;} const int K=110; const ll p=1000000007; int k,m,n; template <typename T> T operator +(T a,T b) { return T(a.first+b.first,a.second+b.second); } template <typename T> T operator *(T a,T b) { return T(a.first*b.first,a.first*b.second+a.second*b.first); } struct mat { pii a[K][K]; mat() { memset(a,0,sizeof a); } pii *operator [](int x) { return a[x]; } }; mat operator *(mat a,mat b) { mat c; for(int i=1;i<=k;i++) for(int j=1;j<=k;j++) { std::pair<__int128,__int128> s; for(int l=1;l<=k;l++) { s.first+=(ll)a[i][l].first*b[l][j].first; s.second+=(ll)a[i][l].first*b[l][j].second; s.second+=(ll)a[i][l].second*b[l][j].first; } c[i][j]=pii(s.first%p,s.second%p); } return c; } mat fp(mat a,ll b) { mat s; for(int i=1;i<=k;i++) s[i][i]=pll(1,0); for(;b;b>>=1,a=a*a) if(b&1) s=s*a; return s; } int b[K][K]; int a[K]; mat c,d; map<int,int> s; int sum(ll l,ll r) { return (l+r)*(r-l+1)/2%p; } int main() { open("jump"); scanf("%d%d%d",&k,&m,&n); k=min(k,n); for(int i=1;i<=k;i++) scanf("%d",&a[i]); for(int i=k;i>=2;i--) a[i]-=a[i-1]; if(a[1]>m) { printf("0\n"); return 0; } for(int i=2;i<=k;i++) if(a[i]>m) k=i; for(int i=1;i<=k;i++) { b[i][i]=1; for(int j=1;j<i;j++) { int flag=1; if(a[1]>a[i-j+1]) flag=0; for(int l=2;flag&&l<=j;l++) if(a[l]!=a[i-j+l]) flag=0; b[i][j]=flag; } } for(int i=1;i<=k;i++) { int cnt=m-a[1]+1; ll _s=sum(a[1],m); s.clear(); for(int j=min(i,k-1);j>=1;j--) if(b[i][j]&&!s[a[j+1]]) { s[a[j+1]]=1; c[i][j+1]=pll(1,a[j+1]); if(a[j+1]>=a[1]) { cnt--; _s=(_s-a[j+1])%p; } } c[i][1]=pll(cnt,_s); } d[1][1]=pll(m-a[1]+1,sum(a[1],m)); c=fp(c,n-1); d=d*c; // for(int i=1;i<n;i++) // d=d*c; ll ans=0; for(int i=1;i<=k;i++) ans=(ans+d[1][i].second)%p; ans=(ans%p+p)%p; printf("%lld\n",ans); return 0; }