「LibreOJ β Round #7」匹配字串
阿新 • • 發佈:2018-12-24
「LibreOJ β Round #7」匹配字串
時間限制: 2 Sec 記憶體限制: 512 MB
題目描述
對於一個 01 串(即由字元 0 和 1 組成的字串)sss,我們稱 sss 合法,當且僅當串 sss 的
任意一個長度為 mmm 的子串 s′s's′,不為全 1 串。
請求出所有長度為 nnn 的 01 串中,有多少合法的串,答案對 655376553765537 取模。
輸入格式
輸入共一行,包含兩個正整數 n,mn,mn,m。
輸出格式
輸出共一行,表示所求的和對 655376553765537 取模的結果。
樣例
樣例輸入 1
5 2
樣例輸出 1
13
樣例解釋 1
以下是所有合法的串:
00000
00001
00010
00100
00101
01000
01001
01010
10000
10001
10010
10100
10101
樣例輸入 2
2018 7
樣例輸出 2
27940
資料範圍與提示
對於所有的資料,滿足 1≤n,m≤687215739041\le n,m\le 687215739041≤n,m≤68721573904。
詳細的資料限制及約定如下(留空表示和上述所有資料的約定相同):
Subtask # | 分值 | nnn | mmm |
---|---|---|---|
1 | 666 | ≤18\le 18≤18 | ≤18\le 18≤18 |
2 | 777 | ≤109\le 10^9≤109 | ≤2\le 2≤2 |
3 | 151515 | ≤106\le 10^6≤106 | ≤106\le 10^6≤106 |
4 | 101010 | ≤109\le 10^9≤109 | ≤50\le 50≤50 |
5 | 141414 | ≤109\le 10^9≤109 | ≤500\le 500≤500 |
6 | 151515 | ≤4295098369\le 4295098369≤4295098369 | - |
7 | 181818 | ≤17180393476\le 17180393476≤17180393476 | - |
8 | 151515 |
題目連結:http://118.24.30.237/problem.php?id=2991
AC 程式碼:
#include<stdio.h>
#include<string.h>
typedef long long ll;
#define mod 65537
ll m,n;
ll f[6005],g[6005],tp[6005];
void mul(ll *a,ll *b)
{
for(int i=0;i<=2*m;i++) tp[i]=0;
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
tp[i+j]=(tp[i+j]+a[i]*b[j])%mod;
for(int i=2*m-2;i>=m;i--)
{
for(int j=0;j<m;j++)
tp[i-m+j]=(tp[i-m+j]+tp[i])%mod;
tp[i]=0;
}
for(int i=0;i<m;i++) a[i]=tp[i];
}
void ksm1()
{
while(n)
{
if(n&1)mul(g,f);
mul(f,f);
n>>=1;
}
}
void f1()
{
f[1]=1; g[0]=1;
ksm1();
ll s=1,ans=0;
for(int i=0;i<m;i++) ans=(ans+s*g[i])%mod,s=s*2%mod;
printf("%lld\n",(ans%mod+mod)%mod);
}
ll fac[65538],inv[65538];
ll C(ll n,ll m)
{
if(m>n) return 0;
if(n>=mod) return C(n/mod,m/mod)*C(n%mod,m%mod)%mod;
else return fac[n]*inv[m]*inv[n-m]%mod;
}
ll ksm2(ll x,ll k)
{
ll s=1;
while(k)
{
if(k&1) s=s*x%mod;
x=x*x%mod;
k>>=1;
}
return s;
}
ll calc(ll n1)
{
ll ans=0,pw2=ksm2(2,n1),iv=ksm2(ksm2(2,m+1),mod-2);
int lim=n1/(m+1);
for(int i=0;i<=lim;++i)
{
if(i&1) ans-=pw2*C(n1-i*m,i);
else ans+=pw2*C(n1-i*m,i);
pw2=pw2*iv%mod;
}
return (ans%mod+mod)%mod;
}
void f2()
{
fac[0]=inv[0]=1;
for(int i=1;i<mod;i++) fac[i]=fac[i-1]*i%mod;
inv[mod-1]=ksm2(fac[mod-1],mod-2);
for(int i=mod-2;i>=1;i--) inv[i]=inv[i+1]*(i+1)%mod;
printf("%lld\n",(calc(n+1)-calc(n)+mod)%mod);
}
int main()
{
scanf("%lld%lld",&n,&m);
if(m<=3000) f1();
else f2();
return 0;
}