T1:
題解:
考試的時候相當轉化爲多項式,然後就不會了。。
題解:求無窮項的多項式是可以由遞推關係解的!用分式多項式表示就行了!
std維護了多項式,但是由於最後只需要。
維護的值即可。
轉移時的求導比較冗長。
Code:
#include<bits/stdc++.h>
#define maxn 55
using namespace std;
const int mod = 998244353;
int n,z,f,z2,c[maxn][maxn],p[maxn],f0[maxn],f1[maxn],g0[maxn],g1[maxn],g2[maxn];
inline int Pow(int a,int b){
int s=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
return s;
}
inline int Inv(int x){return Pow(x,mod-2);}
int main()
{
freopen("capitalism.in","r",stdin);
freopen("capitalism.out","w",stdout);
scanf("%d%d%d",&n,&z,&f),z2=1ll*z*z%mod;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
scanf("%d",&c[i][j]),p[j]=(p[j]+c[i][j])%mod;
f0[1]=1ll*f*Inv((1-(1ll-f)*z)%mod)%mod;//F(z)
f1[1]=1ll*f*(1-f)%mod*Pow(Inv((1-(1ll-f)*z)%mod),2)%mod;//F'(z)
g0[1]=1ll*f*Inv((1-(1ll-f)*z2)%mod)%mod;//F(z^2)
g1[1]=1ll*f*(1-f)%mod*Pow(Inv((1-(1ll-f)*z2)%mod),2)%mod;//F'(z^2)
g2[1]=2ll*f*(1-f)%mod*(1-f)%mod*Pow(Inv((1-(1ll-f)*z2)%mod),3)%mod;//F''(z^2)
for(int i=2;i<=n;i++){
p[i]=1-p[i];
int d1=Inv((1-1ll*p[i]*z)%mod),d2=Inv((1-1ll*p[i]*z2)%mod);
for(int j=1;j<i;j++){
f0[i]=(f0[i]+1ll*z*c[j][i]%mod*f0[j]%mod*d1)%mod;
f1[i]=(f1[i]+(1ll*c[j][i]*f0[j]+1ll*z*c[j][i]%mod*f1[j])%mod*d1+1ll*z*p[i]%mod*c[j][i]%mod*f0[j]%mod*d1%mod*d1)%mod;
g0[i]=(g0[i]+1ll*z2*c[j][i]%mod*g0[j]%mod*d2)%mod;
g1[i]=(g1[i]+(1ll*c[j][i]*g0[j]+1ll*z2*c[j][i]%mod*g1[j])%mod*d2+1ll*z2*p[i]%mod*c[j][i]%mod*g0[j]%mod*d2%mod*d2)%mod;
g2[i]=(g2[i]+c[j][i]*((2ll*g1[j]+1ll*z2*g2[j]%mod)*d2%mod+2ll*p[i]*(1ll*z2*g1[j]%mod*Pow(d2,2)%mod+1ll*g0[j]*Pow(d2,3)%mod)%mod))%mod;
}
}
printf("%d\n",((1ll*z2*z2%mod*g2[n]+1ll*z2*g1[n]-Pow(1ll*z*f1[n]%mod,2))%mod+mod)%mod);
}
std用vector<pair>存了多項式的次數和係數,分別維護分子多項式和分母多項式:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
typedef long long LL;
const int N=55,M=998244353;
int n,z,f[N],c[N][N];
typedef vector<pair<int,int> > poly;
poly X,u,v,u1,v1,u2,v2;
poly Num[N],Den[N],tmps,tmpa,tmpm,tmpd,tmpc;
int fpw(int a,int b,const int c=M)
{
int s=1;
for(;b;b>>=1,a=(LL)a*a%c)
if(b&1)s=(LL)s*a%c;
return s;
}
int inv(int a,const int b=M)
{
return fpw(a,b-2,b);
}
void simplify(poly &p)
{
sort(p.begin(),p.end());
tmps.clear();
for(int i=0;i<p.size();i++)
{
if(tmps.empty()||tmps.back().first!=p[i].first)
tmps.push_back(p[i]);
else
(tmps.back().second+=p[i].second)%=M;
if(tmps.back().second==0)tmps.pop_back();
}
p=tmps;
}
poly operator+(const poly &a,const poly &b)
{
tmpa.clear();
for(int i=0;i<a.size();i++)
tmpa.push_back(a[i]);
for(int i=0;i<b.size();i++)
tmpa.push_back(b[i]);
simplify(tmpa);
return tmpa;
}
poly operator-(const poly &a,const poly &b)
{
tmpa.clear();
for(int i=0;i<a.size();i++)
tmpa.push_back(a[i]);
for(int i=0;i<b.size();i++)
tmpa.push_back(make_pair(b[i].first,M-b[i].second));
simplify(tmpa);
return tmpa;
}
poly operator*(const poly &a,const poly &b)
{
tmpm.clear();
for(int i=0;i<a.size();i++)
for(int j=0;j<b.size();j++)
tmpm.push_back(make_pair(a[i].first+b[j].first,(LL)a[i].second*b[j].second%M));
simplify(tmpm);
return tmpm;
}
poly operator*(const poly &a,const int &b)
{
tmpc=a;
for(int i=0;i<tmpc.size();i++)
tmpc[i].second=(LL)tmpc[i].second*b%M;
return tmpc;
}
poly derivative(const poly &a)
{
tmpd.clear();
for(int i=0;i<a.size();i++)
if(a[i].first!=0)
tmpd.push_back(make_pair(a[i].first-1,(LL)a[i].second*a[i].first%M));
return tmpd;
}
int calc(const poly &a,int x)
{
int res=0;
for(int i=0;i<a.size();i++)
res=(res+(LL)fpw(x,a[i].first)*a[i].second)%M;
return res;
}
#include<ctime>
int main()
{
freopen("capitalism.in","r",stdin);
freopen("capitalism.out","w",stdout);
X.push_back(make_pair(1,1));
scanf("%d%d%d",&n,&z,f+1);
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
scanf("%d",&c[i][j]),(f[j]+=c[i][j])%=M;
Num[1].push_back(make_pair(0,f[1]));
Den[1].push_back(make_pair(0,1));
Den[1].push_back(make_pair(1,(M-(1-f[1]))%M));
for(int i=2;i<=n;i++)
{
Den[i].push_back(make_pair(0,1));
Den[i].push_back(make_pair(1,(M-(1-f[i]))%M));
for(int j=1;j<i;j++)
Num[i]=Num[i]+X*Num[j]*c[j][i];
for(int j=1;j<i;j++)
{
Den[j]=Den[j]*Den[i];
Num[j]=Num[j]*Den[i];
}
Den[i]=Den[i-1];
}
u=Num[n];
v=Den[n];
u1=derivative(u)*v-u*derivative(v);
v1=v*v;
u1=u1*X;
u2=derivative(u1)*v1-u1*derivative(v1);
v2=v1*v1;
u2=u2*X;
int z2=(LL)z*z%M;
int E1=(LL)calc(u1,z)*inv(calc(v1,z))%M;
int E2=(LL)calc(u2,z2)*inv(calc(v2,z2))%M;
int ans=(E2-(LL)E1*E1)%M;
if(ans<0)ans+=M;
printf("%d\n",ans);
//cout<<clock()<<endl;
return 0;
}
T2:
題解:
既然實力值高的人獲勝的概率是定值,那麼一個人是誰就不重要,他的實力值具體是多少也不重要,重要的是他的排名。這樣就可以把狀態數壓縮,只需要記表示個人中排名第位的人勝出的概率。
把與無關項提前,其餘項儘量寫成與形式。
Code:
#include<bits/stdc++.h>
#define maxn (1<<20)+5
using namespace std;
const int mod = 998244353, G = 3;
int n,p,A,B,C,D,E,ans,v[maxn],f[maxn],a[maxn],b[maxn],tmp[maxn],fac[maxn],inv[maxn];
inline int Pow(int a,int b){
int s=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
return s;
}
int w[maxn],r[maxn],wlen;
void init(const int N){
fac[0]=inv[0]=1;
for(int i=1;i<=N;i++) fac[i]=1ll*fac[i-1]*i%mod;
inv[N]=Pow(fac[N],mod-2);
for(int i=N-1;i>=1;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
wlen=N,w[0]=1,w[1]=Pow(G,(mod-1)/wlen);
for(int i=2;i<=wlen;i++) w[i]=1ll*w[i-1]*w[1]%mod;
}
void NTT(int *a,int len,int flg){
for(int i=0;i<len;i++) if(i<(r[i]=r[i>>1]>>1|(i&1?len>>1:0))) swap(a[i],a[r[i]]);
for(int i=2;i<=len;i<<=1)
for(int j=0,t=wlen/i;j<len;j+=i)
for(int k=j,o=0;k<j+i/2;k++,o+=t){
int u=a[k],v=1ll*w[flg==1?o:wlen-o]*a[k+i/2]%mod;
a[k]=(u+v)%mod,a[k+i/2]=(u-v)%mod;
}
if(flg==-1) for(int i=0,Inv=Pow(len,mod-2);i<len;i++) a[i]=1ll*a[i]*Inv%mod;
}
void solve(int m){
for(int i=0;i<m;i++)//!!!
a[i]=1ll*f[i]*inv[i]%mod*inv[m-1-i]%mod,
tmp[i+1]=(tmp[i]+f[i])%mod;
for(int i=0;i<=m;i++)//!!!
b[i]=(1ll*tmp[i]*(1-p)+1ll*(tmp[m]-tmp[i])*p)%mod*inv[i]%mod*inv[m-i]%mod;
NTT(a,m<<1,1),NTT(b,m<<1,1);
for(int i=0;i<m<<1;i++) f[i]=1ll*a[i]*b[i]%mod;
NTT(f,m<<1,-1);
for(int i=0,c=1ll*inv[m+m]*fac[m]%mod*fac[m]%mod;i<m<<1;i++)
f[i]=2ll*f[i]*fac[i]%mod*fac[m+m-1-i]%mod*c%mod;
}
int main()
{
freopen("comparison.in","r",stdin);
freopen("comparison.out","w",stdout);
scanf("%d%d%d%d%d%d%d",&n,&p,&A,&B,&C,&D,&E);
for(int i=0;i<1<<n;i++) v[i]=A%E,A=(1ll*A*B+C)%D;
init(1<<n);
f[0]=1;
for(int i=0;i<n;i++) solve(1<<i);
sort(v,v+(1<<n),greater<int>());
for(int i=0;i<1<<n;i++) ans=(ans+1ll*v[i]*f[i])%mod;
printf("%d\n",(ans+mod)%mod);
}
T3:
題解:
做法就是同構字符串的KMP,【COCI 2011-2012 contest#4】decode,將每個位置的值改寫爲與前一個相同的值的位置之差,由於KMP比較時需要與區間左端點取max,所以不好擴展。
因爲變化的位置是的,所以建出關聯數列的後綴數組後比較兩個關聯數列變化後的子串可以做到,於是可以通過建出關聯後綴的後綴數組並求出其height值,求子串的出現次數時二分兩邊範圍即可。
Code:
#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
char cb[1<<18],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
int n,Q,a[maxn],nxt[maxn][10],pos[maxn][12];
char s[maxn];
namespace SA{
const int Log = 16;
int ary[4][maxn],b[maxn],lg[maxn]={-1},st[maxn][Log+1];
int *sa=ary[0],*rk=ary[1],*nsa=ary[2],*nrk=ary[3];
void build(int n,int m,int *a){
for(int i=1;i<=n;i++) b[a[i]]++;
for(int i=1;i<=m;i++) b[i]+=b[i-1];
for(int i=1;i<=n;i++) sa[b[a[i]]--]=i;
for(int i=1;i<=n;i++) rk[sa[i]]=rk[sa[i-1]]+(a[sa[i-1]]!=a[sa[i]]);
for(int k=1;rk[sa[n]]<n;k<<=1){
for(int i=1;i<=n;i++) b[rk[sa[i]]]=i;
for(int i=n;i>=1;i--) if(sa[i]-k>0) nsa[b[rk[sa[i]-k]]--]=sa[i]-k;
for(int i=n-k+1;i<=n;i++) nsa[b[rk[i]]--]=i;
for(int i=1;i<=n;i++) nrk[nsa[i]]=nrk[nsa[i-1]]+(rk[nsa[i-1]]!=rk[nsa[i]]||rk[nsa[i-1]+k]!=rk[nsa[i]+k]);
swap(sa,nsa),swap(rk,nrk);
}
for(int i=1,j,k=0;i<=n;st[rk[i]][0]=k,i++)
for(k&&(k--),j=sa[rk[i]-1];a[i+k]==a[j+k];k++);
for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int j=1;j<=Log;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
inline int LCP(int x,int y){
if(x==y) return n-x+1;
if((x=rk[x])>(y=rk[y])) swap(x,y); x++;
int k=lg[y-x+1];
return min(st[x][k],st[y-(1<<k)+1][k]);
}
}
namespace SA2{
const int Log = 16;
int sa[maxn],rk[maxn],lg[maxn]={-1},st[maxn][Log+1];
typedef pair<bool,int> pii;
pii solve(int x,int y){
int i=1,*p=pos[x],*q=pos[y];
for(int lim=min(*p,*q);i<=lim;i++){
if(p[i]!=q[i]) return pii(p[i]<q[i],min(p[i],q[i]));
int len=p[i]+SA::LCP(x+p[i]+1,y+q[i]+1)+1;
if(len<min(p[i+1],q[i+1])) return pii(a[x+len]<a[y+len],len);
}
return pii(p[i]==q[i]?i>*p:p[i]<q[i],min(p[i],q[i]));
}
bool cmp(int i,int j){return solve(i,j).first;}
void build(){
for(int i=1;i<=n;i++) sa[i]=i;
sort(sa+1,sa+1+n,cmp);
for(int i=1;i<=n;i++) rk[sa[i]]=i,i>1&&(st[i][0]=solve(sa[i],sa[i-1]).second);
/*for(int i=1;i<=n;i++){
for(int j=1;j<=*pos[sa[i]];j++){
printf("0 ");
for(int k=pos[sa[i]][j]+1;k<pos[sa[i]][j+1];k++) printf("%d ",a[sa[i]+k]);
}
putchar('\n');
}*/
for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int j=1;j<=Log;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
inline int LCP(int x,int y){
if(x==y) return n-x+1;
if((x=rk[x])>(y=rk[y])) swap(x,y); x++;
int k=lg[y-x+1];
return min(st[x][k],st[y-(1<<k)+1][k]);
}
void work(int x,int y){
int L,R,l,r,mid;
for(l=1,r=rk[x];l<r;) mid=(l+r)>>1,LCP(sa[mid],x)>=y-x+1?(r=mid):(l=mid+1);
L=l;
for(l=rk[x],r=n;l<r;) mid=(l+r+1)>>1,LCP(sa[mid],x)>=y-x+1?(l=mid):(r=mid-1);
R=l;
printf("%d\n",R-L+1);
}
}
int main()
{
freopen("conscience.in","r",stdin);
freopen("conscience.out","w",stdout);
scanf("%d%d%s",&n,&Q,s+1);
for(int i=n,c;i>=1;i--){
memcpy(nxt[i],nxt[i+1],10<<2);
c=s[i]-'0',a[nxt[i][c]]=nxt[i][c]-i,nxt[i][c]=i;
for(int j=0;j<=9;j++) if(nxt[i][j]) pos[i][++*pos[i]]=nxt[i][j]-i;
sort(pos[i]+1,pos[i]+1+*pos[i]),pos[i][*pos[i]+1]=n+1-i;
}
a[n+1]=a[0]=-1,SA::build(n,n,a);
SA2::build();
int l,r;
while(Q--) read(l),read(r),SA2::work(l,r);
}