【TJOI2019 Day1】简要题解
T1:
传送门
傻逼题,一个裸的矩乘就完了
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
const int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
struct mat{
int a[26][26];
mat(){memset(a,0,sizeof(a));}
friend inline mat operator *(cs mat &a,cs mat &b){
mat c;
for(int i=0;i<26;i++)
for(int k=0;k<26;k++)
for(int j=0;j<26;j++)
Add(c.a[i][j],mul(a.a[i][k],b.a[k][j]));
return c;
}
};
inline mat ksm(mat a,ll b){
mat res;
for(int i=0;i<26;i++)res.a[i][i]=1;
for(;b;b>>=1,a=a*a)if(b&1)res=res*a;
return res;
}
mat got;
ll n;
int res;
char s[100005];
int main(){
cin>>n;
scanf("%s",s+1);
for(int i=0;i<26;i++)for(int j=0;j<26;j++)got.a[i][j]=1;
for(int i=1,len=strlen(s+1);i<len;i++){
got.a[s[i]-'a'][s[i+1]-'a']=0;
}
got=ksm(got,n-1);
for(int i=0;i<26;i++)
for(int j=0;j<26;j++)
Add(res,got.a[i][j]);
cout<<res;
}
T2:
传送门
傻逼题,一个裸的平衡树就完了
不过很容易
会快很多
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
#define uint unsigned int
const int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=2000005;
int n,m;
uint seed,last=7;
namespace RAND{
typedef unsigned int ui;
inline ui Rand() {
seed = seed * 17 + last;
return seed % m + 1;
}
}
using RAND::Rand;
namespace treap{
int son[N][2],siz[N],key[N],rt,tot;
pii val[N];
#define lc(u) son[u][0]
#define rc(u) son[u][1]
int sd=233;
inline int rnd(){
return sd=int(sd*482711ll%2147483647);
}
inline void init(){
for(int i=1;i<N;i++)key[i]=rnd();
}
inline void clear(){
rt=tot=0;
}
inline int newnode(pii k){
int u=++tot;siz[u]=1,lc(u)=rc(u)=0,val[u]=k;
return u;
}
inline void pushup(int u){
siz[u]=siz[lc(u)]+siz[rc(u)]+1;
}
inline void split(int r1,int &a,int &b,pii k){
if(r1==0){a=b=0;return;}
if(val[r1]<=k){
a=r1,split(rc(r1),rc(a),b,k);
}
else b=r1,split(lc(r1),a,lc(b),k);
pushup(r1);
}
inline void merge(int &r1,int a,int b){
if(!a||!b){r1=a+b;return;}
if(key[a]<key[b]){r1=a,merge(rc(r1),rc(a),b);}
else r1=b,merge(lc(r1),a,lc(b));
pushup(r1);
}
inline void insert(pii k){
int u=newnode(k),r1,r2;
split(rt,r1,r2,k);
merge(r1,r1,u);
merge(rt,r1,r2);
}
inline void delet(pii k){
int r1,r2,r3;
split(rt,r1,r2,pii(k.fi,k.se-1));
split(r2,r2,r3,k);
merge(r2,lc(r2),rc(r2));
merge(r1,r1,r2);
merge(rt,r1,r3);
}
inline int getrk(pii k){
int r1,r2;
split(rt,r1,r2,pii(k.fi,k.se-1));
int res=siz[r1];
merge(rt,r1,r2);return res;
}
}
pii p[N];
int main(){
int T=read();
treap::init();
while(T--){
treap::clear();
m=read(),n=read(),seed=read();
//for(int i=1;i<=m;i++)treap::insert(p[i]);
for(int i=1;i<=n;i++){
int x=Rand(),y=Rand();
if(p[x].fi)treap::delet(p[x]);
p[x].fi--,p[x].se+=y;
treap::insert(p[x]);
cout<<(last=treap::getrk(p[x]))<<'\n';
}
for(int i=1;i<=m;i++)p[i]=pii(0,0);
}
}
T3:
传送门
律师函警告
一个显然的思路是求出至少组讨论的方案后容斥
考虑这组人位置的方案数显然是
然后考虑剩下的怎么放
对每种人构建
用直接乘起来取次项就是了
模数很友好
好像直接暴力卷积都可以过
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
#define uint unsigned int
#define poly vector<int>
const int mod=998244353,G=3;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=1005;
int fac[N],ifac[N],s[N],g[N][N],f[N],ans[N];
int n,a,b,c,d,mx;
int rev[N<<2];
poly w[14];
inline void init_w(){
cs int C=13;
for(int i=1;i<=C;i++)w[i].resize(1<<(i-1));
int wn=ksm(G,(mod-1)/(1<<C));
w[C][0]=1;
for(int i=1;i<=(1<<(C-1));i++)w[C][i]=mul(w[C][i-1],wn);
for(int i=C-1;i;i--)
for(int j=0;j<(1<<(i-1));j++)
w[i][j]=w[i+1][j<<1];
}
inline void init_rev(int lim){
for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));
}
inline void ntt(poly &f,int lim,int kd){
for(int i=0;i<lim;i++)if(i>rev[i])swap(f[i],f[rev[i]]);
for(int mid=1,l=1,a0,a1;mid<lim;mid<<=1,l++)
for(int i=0;i<lim;i+=(mid<<1))
for(int j=0;j<mid;j++)
a0=f[i+j],a1=mul(w[l][j],f[i+j+mid]),f[i+j]=add(a0,a1),f[i+j+mid]=dec(a0,a1);
if(kd==-1){
reverse(f.bg()+1,f.bg()+lim);
for(int i=0,inv=Inv(lim);i<lim;i++)Mul(f[i],inv);
}
}
inline void init(){
cs int len=N-5;
fac[0]=ifac[0]=1;
for(int i=1;i<=len;i++)fac[i]=mul(fac[i-1],i);
ifac[len]=Inv(fac[len]);
for(int i=len-1;i;i--)ifac[i]=mul(ifac[i+1],i+1);
}
inline int C(int n,int m){
return n<m?0:mul(fac[n],mul(ifac[m],ifac[n-m]));
}
inline int calc(int x){
int res=C(n-3*x,x),lim=1;
poly A,B,C,D;
for(int i=0;i<=a-x;i++)A.pb(ifac[i]);
for(int i=0;i<=b-x;i++)B.pb(ifac[i]);
for(int i=0;i<=c-x;i++)C.pb(ifac[i]);
for(int i=0;i<=d-x;i++)D.pb(ifac[i]);
int deg=A.size()+B.size()+C.size()+D.size()-3;
while(lim<deg)lim<<=1;
init_rev(lim);
A.resize(lim),ntt(A,lim,1);
B.resize(lim),ntt(B,lim,1);
C.resize(lim),ntt(C,lim,1);
D.resize(lim),ntt(D,lim,1);
for(int i=0;i<lim;i++)A[i]=1ll*A[i]*B[i]%mod*C[i]%mod*D[i]%mod;
ntt(A,lim,-1),A.resize(deg);
return mul(res,mul(A[n-4*x],fac[n-4*x]));
}
int main(){
init(),init_w();
n=read(),a=read(),b=read(),c=read(),d=read(),mx=min(min(a,b),min(c,d)),mx=min(mx,n/4);
for(int i=0;i<=mx;i++){
f[i]=calc(i);
}
int res=0;
for(int j=0;j<=mx;j++)
if(j&1)Dec(res,f[j]);
else Add(res,f[j]);
cout<<res;
}