题解:P11284 「GFOI Round 2」Strings
本文除法全部下取整。
设
枚举答案序列最短偶回文前缀
容易发现答案可以被函数
考虑递归计算,使用与对答案类似的处理技巧:
前面部分可以等比数列求和,后半部分:
发现
时间复杂度
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<cstdio>
#include<random>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
#define IV void
#define her1 20081214
#define cht 1000000007
#define ull unsigned long long
#define mem(x,val) memset(x,val,sizeof x)
#define F(i,j,n)for(register int i=j;i<=n;i++)
#define D(i,j,n)for(register int i=j;i>=n;i--)
#define E(i,now)for(register int i=first[now];i;i=e[i].nxt)
#define FL(i,j,n)for(register i64 i=j;i<=n;i++)
#define DL(i,j,n)for(register i64 i=j;i>=n;i--)
#define EL(i,now)for(register i64 i=first[now];i;i=e[i].nxt)
ll read(){
ll ans=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9')ans=ans*10+c-'0',c=getchar();
return ans*f;
}
#undef ll
#include "assert.h"
mt19937_64 rnd(her1);
#include "functional"
using i64 = long long;
i64 qpow(i64 n,i64 base=cht-2){
base%=(cht-1);n%=cht;
if(base<0)base+=cht-1;
i64 ans=1;
while(base){
if(base&1)ans=ans*n%cht;
n=n*n%cht;base>>=1;
}
return ans;
}
IV cadd(i64&x,i64 val){x=(x+val)%cht;}
const int maxn = 1e5+5;
i64 n,m;
map<pair<i64,i64>,i64>mp;
i64 S(i64 n,i64 k){
if(n==1)return qpow(m,k+1);
if(mp.count({n,k}))return mp[{n,k}];
i64 Ans=0,pw=qpow(m,k+1);
if(pw==1)Ans=n;
else Ans=qpow(pw-1)*(qpow(pw,n+1)-qpow(pw,1))%cht;
i64 s=(S(n/2,2*k)-S(n/2,-2)*qpow(m,(n%(cht-1)+1)*(k%(cht-1)+1)))%cht;
s=s*qpow(1-qpow(m,k+1))%cht;
return mp[{n,k}]=(Ans-s)%cht;
}
IV solve(){
n=read();m=read();mp.clear();
if(m==1)return(void)(printf("%lld\n",(n-2)%cht));
i64 Ans=(S(n/3,1)-S(n/3,-2)*qpow(m,n+1))%cht;
printf("%lld\n",(Ans*qpow(1-m)%cht+cht)%cht);
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
i64 T=read();while(T--)solve();return 0;
}