q%100000,不是正解。
题解是要生成函数+二次剩余。
蔡队说,k进制快速幂。
////////////////////////////
然后晚上终于学会了k进制快速幂。感谢蔡队。
在后边放了代码。
/////////////////////////////
二进制矩阵快速幂做法 +q%100000(232ms):
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=998244353; const int maxn=1e3+50; const int inf=0x3f3f3f3f; ll jkpow(ll n) { int i,j,k,t; ll ans[2]={1,0}; ll base[2][2]={3,2,1,0}; ll tempa[2],tempb[2][2]; while(n) { if(n&1) { memset(tempa,0,sizeof(tempa)); for(i=0;i<2;i++) for(j=0;j<2;j++) tempa[i]=(tempa[i]+base[i][j]*ans[j]%mod)%mod; for(i=0;i<2;i++)ans[i]=tempa[i]%mod; } memset(tempb,0,sizeof(tempb)); for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++) tempb[i][j]=(tempb[i][j]+base[i][k]*base[k][j]%mod)%mod; for(i=0;i<2;i++) for(j=0;j<2;j++) base[i][j]=tempb[i][j]%mod; n>>=1; } return ans[0]%mod; } int main() { ll q,n,a,ans=-1; scanf("%lld%lld",&q,&n); if(q>100000)q=100000; for(int i=1;i<=q;i++) { if(n)a=jkpow(n-1);else a=0; n^=(a*a); if(ans==-1)ans=a; else ans^=a; } printf("%lld ",ans); }
带初始化优化的二进制矩阵快速幂做法+q%100000(71ms):
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=998244353; const int maxn=1e3+50; const int inf=0x3f3f3f3f; ll base[70][2][2]; void init() { int i,j,k,u; base[1][0][0]=3;base[1][0][1]=2;base[1][1][0]=1;base[1][1][1]=0; ll tempb[2][2]; for(u=2;u<=64;u++) { memset(tempb,0,sizeof(tempb)); for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++) tempb[i][j]=(tempb[i][j]+base[u-1][i][k]*base[u-1][k][j]%mod)%mod; for(i=0;i<2;i++) for(j=0;j<2;j++) base[u][i][j]=tempb[i][j]%mod; } } ll jkpow(ll n) { int i,j,k,t,u=1; ll ans[2]={1,0}; ll tempa[2],tempb[2][2]; while(n) { if(n&1) { memset(tempa,0,sizeof(tempa)); for(i=0;i<2;i++) for(j=0;j<2;j++) tempa[i]=(tempa[i]+base[u][i][j]*ans[j]%mod)%mod; for(i=0;i<2;i++)ans[i]=tempa[i]%mod; } memset(tempb,0,sizeof(tempb)); u++; n>>=1; } return ans[0]%mod; } int main() { init(); ll q,n,a,ans=-1; scanf("%lld%lld",&q,&n); if(q>100000)q=100000; for(int i=1;i<=q;i++) { if(n-1)a=jkpow(n-1);else a=0; n^=(a*a); if(ans==-1)ans=a; else ans^=a; if(!a)break; } printf("%lld ",ans); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
k进制快速幂!虽说是995ms,但好歹是实打实跑了1e7的询问。上面的代码也只能跑1e6吧。
大写 开心! 感谢蔡队!
(矩阵的看不懂参照看下一份代码的整数k进制快速幂代码,附了简单的注释)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=998244353; const int maxn=1e3+50; const int inf=0x3f3f3f3f; //65535 ll base[5][65540][2][2]; void init() { int i,j,k,u,t; base[0][1][0][0]=3;base[0][1][0][1]=2; base[0][1][1][0]=1;base[0][1][1][1]=0; ll tempb[5][2][2]; for(t=0;t<=3;t++) { if(t) { for(i=0;i<2;i++) for(j=0;j<2;j++) base[t][1][i][j]=base[t-1][65536][i][j]; } for(u=2;u<=65536;u++) { memset(tempb,0,sizeof(tempb)); for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++) tempb[t][i][j]=(tempb[t][i][j]+base[t][1][i][k]*base[t][u-1][k][j]%mod)%mod; for(i=0;i<2;i++) for(j=0;j<2;j++) base[t][u][i][j]=tempb[t][i][j]%mod; } } } ll jkpow(ll n) { int i,j,k,t,u=0,re; ll ans[2]={1,0}; ll tempa[2]; ll tbase[2][2]; while(n) { re=n%65536; if(re) { memset(tempa,0,sizeof(tempa)); for(i=0;i<2;i++) for(j=0;j<2;j++) tempa[i]=(tempa[i]+base[u][re][i][j]*ans[j]%mod)%mod; for(i=0;i<2;i++)ans[i]=tempa[i]%mod; } u++; n/=65536; } return ans[0]%mod; } int main() { init(); ll q,n,a,ans=-1; scanf("%lld%lld",&q,&n); for(int i=1;i<=q;i++) { if(n-1)a=jkpow(n-1);else a=0; n^=(a*a); if(ans==-1)ans=a; else ans^=a; if(!a)break; } printf("%lld ",ans); }
上边是矩阵的
我再贴一个整数的k进制快速幂。
/* k进制快速幂 对同一个基数来说 大数幂可以加快 对不同基数 或者是 正常幂 很鸡肋 甚至有毒 */ #include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=998244353; const int maxn=1e2+50; const int inf=0x3f3f3f3f; ll kpow(ll a,ll b) { ll ans=1; while(b) { if(b&1)ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } ll base[6][65540]; //base[i][1]是基数a的i+1次方 //base[i][j]是base[i][1]的j倍。 void init(ll a,ll k) { base[0][1]=a%mod; int up=3;//up 根据最大数(龙龙)开k次方根的大小来估算 for(int i=1;i<=up;i++)base[i][0]=1; for(int i=0;i<=up;i++) { if(i)base[i][1]=base[i-1][k]; for(int j=2;j<=k;j++) { base[i][j]=base[i][j-1]*base[i][1]%mod; } } } ll K65536_pow(ll a,ll b) { int k=65536; init(a,k); ll ans=1,i=0; while(b) { ans=ans*base[i++][b%k]%mod; b/=k; } return ans; } int main() { ll T; scanf("%d",&T); while(T--) { ll a,b; cin>>a>>b; cout<<kpow(a,b)<<" "<<K65536_pow(a,b)<<endl; } }
2019-09-09 00:10:40