国庆模拟赛四
T1
结论:直接输出TIE
T2
树剖,然后有古神的神奇结论:
1.对于一个查询只用管他两个链的端点的答案
2.建线段树之后两个点之间答案为他们左右儿子两两组合的较大值
就这样,还没改出来……毁灭吧
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls now<<1
#define rs now<<1|1
const ll N=114514,M=1919810;
struct xx{
ll next,to;
}e[2*N];
ll head[2*N],cnt;
void add(ll x,ll y){
e[++cnt].next=head[x];
e[cnt].to=y;
head[x]=cnt;
}
ll dept[N],size[N],son[M],f[N];
ll dfn[N],st[N],to[N],t_cnt;
void dfs1(ll u,ll fa){
size[u]=1;
for(int i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa) continue;
dept[v]=dept[u]+1; f[v]=u;
dfs1(v,u);
size[u]+=size[v];
if(size[son[u]]<size[v]) son[u]=v;
}
}
void dfs2(ll u,ll top){
st[u]=top,dfn[u]=++t_cnt,to[t_cnt]=u;
if(son[u]) dfs2(son[u],top);
for(int i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(dfn[v]) continue;
dfs2(v,v);
}
}
ll query_lca(ll u,ll v){
while(st[u]!=st[v]){
if(dept[st[u]]<dept[st[v]]) swap(u,v);
u=f[st[u]];
}
if(dept[u]>dept[v]) swap(u,v);
return u;
}
ll n,q;
struct gx{
ll u,v;
}ys[N];
struct tree{
ll l,r,lca,val;
bool operator <(const tree &lxl)const{
return val<lxl.val;
}
tree(){l=r=lca=val=0;}
}t[4*N];
/*古神的神奇结论:
1.对于一个查询只用管他两个链的端点的答案
2.建线段树之后两个点之间答案为他们左右儿子两两组合的较大值???*/
tree merge(tree x,tree y){
if(!x.l||!y.l) return max(x,y);
tree c,d,e,f;
c.l=x.l,c.r=y.l;
d.l=x.l,d.r=y.r;
e.l=x.r,e.r=y.l;
f.l=x.r,f.l=y.r;
c.lca=query_lca(c.l,c.r);
d.lca=query_lca(d.l,d.r);
e.lca=query_lca(e.l,e.r);
f.lca=query_lca(f.l,f.r);
c.val=dept[c.l]+dept[c.r]-2*dept[c.lca];
d.val=dept[d.l]+dept[d.r]-2*dept[d.lca];
e.val=dept[e.l]+dept[e.r]-2*dept[e.lca];
f.val=dept[f.l]+dept[f.r]-2*dept[f.lca];
return max(max(max(max(max(x,y),c),d),e),f);
}
void pushup(ll now){
t[now]=merge(t[ls],t[rs]);
}
void build(ll now,ll l,ll r){
if(l==r){
t[now].l=ys[to[l]].u;
t[now].r=ys[to[l]].v;
t[now].lca=query_lca(t[now].l,t[now].r);
t[now].val=dept[t[now].l]+dept[t[now].r]-2*dept[t[now].lca];
return;
}
ll mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(now);
}
void update(ll now,ll l,ll r,ll x,ll y,ll z){
if(l==r){
t[now].l=y;
t[now].r=z;
t[now].lca=query_lca(y,z);
t[now].val=dept[y]+dept[z]-2*dept[t[now].lca];
return;
}
ll mid=l+r>>1;
if(x<=mid) update(ls,l,mid,x,y,z);
else update(rs,mid+1,r,x,y,z);
pushup(now);
}
tree query(ll now,ll l,ll r,ll x,ll y){
if(l>=x&&r<=y) return t[now];
tree ans;
ll mid=l+r>>1;
if(x<=mid) ans=merge(ans,query(ls,l,mid,x,y));
if(y>mid) ans=merge(ans,query(rs,mid+1,r,x,y));
return ans;
}
ll query_ans(ll u,ll v){
tree ans;
while(st[u]!=st[v]){
if(dept[st[u]]<dept[st[v]]) swap(u,v);
ans=merge(ans,query(1,1,n,dfn[st[u]],dfn[u]));
u=f[st[u]];
}
if(dept[u]>dept[v]) swap(u,v);
ans=merge(ans,query(1,1,n,dfn[u],dfn[v]));
return ans.val;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>q;
for(int i=1;i<n;++i){
ll a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
dept[1]=1,dfs1(1,0); dfs2(1,1);
for(int i=1;i<=n;++i) cin>>ys[i].u>>ys[i].v;
build(1,1,n);
for(int i=1;i<=n;++i) cout<<"QWQ: "<<t[i].lca<<'\n';
while(q--){
ll opt,x,y,z;
cin>>opt>>x>>y;
if(opt==1){
cin>>z;
update(1,1,n,dfn[x],y,z);
}
else cout<<query_ans(x,y)<<'\n';
}
return 0;
}
T3
在这里自己看link
T4
诡异dp能 做出来,还有 的生成函数做法,都不会。
摆了
标程的生成函数代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 5505
#define M 200005
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
int read(){
int w=0,h=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')h=-h;ch=getchar();}
while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
return w*h;
}
const int mod=998244353,g=3,ig=332748118,B=25000;
namespace Polynomial{
int pwg[B+1],PWG[B+1],pwig[B+1],PWIG[B+1],inv[M],lg[M],pw[M];
void add(int&x,int y){(x+=y)>=mod?x-=mod:x;}
inline void Init(){
for(int i=pwg[0]=1;i<=B;i++)pwg[i]=pwg[i-1]*g%mod;
for(int i=PWG[0]=1;i<=B;i++)PWG[i]=PWG[i-1]*pwg[B]%mod;
for(int i=pwig[0]=1;i<=B;i++)pwig[i]=pwig[i-1]*ig%mod;
for(int i=PWIG[0]=1;i<=B;i++)PWIG[i]=PWIG[i-1]*pwig[B]%mod;
for(int i=pw[0]=inv[1]=1;i<M;i++)pw[i]=pw[i-1]*2%mod;
for(int i=2;i<M;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod,lg[i]=lg[i>>1]+1;
}
inline int qpow(int k){
if(k==0)return 1;
if(k>0)return PWG[k/B]*pwg[k%B]%mod;
if(k<0)return PWIG[(-k)/B]*pwig[(-k)%B]%mod;
return 114514;
}
inline int qpow(int b,int k){
int s=1;
while(k){
if(k&1)s=s*b%mod;
b=b*b%mod;k>>=1;
}
return s;
}
struct Poly{
#define ite vector<int>::iterator
#define rite vector<int>::reverse_iterator
vector<int>f;
Poly(){f=vector<int>(0);}
Poly(int x=0,int y=0){f=vector<int>(x,y);}
Poly(vector<int>x=vector<int>(0)){f=x;}
inline int size(){return f.size();}
inline int back(){return f.back();}
inline bool empty(){return f.empty();}
inline int&operator[](int x){return f[x];}
inline ite begin(){return f.begin();}
inline ite end(){return f.end();}
inline rite rbegin(){return f.rbegin();}
inline rite rend(){return f.rend();}
inline void swap(Poly&b){vector<int>tmp=f;f=b.f;b.f=tmp;}
inline void sort(ite BEGIN,ite END){sort(BEGIN,END);}
inline void sort(rite BEGIN,rite END){sort(BEGIN,END);}
inline void reverse(ite BEGIN,ite END){reverse(BEGIN,END);}
inline void emplace_back(int x){f.emplace_back(x);}
inline void clear(){f.clear();}
inline void erase(ite x){f.erase(x);}
inline void pop_back(){f.pop_back();}
inline void resize(int x){f.resize(x);}
inline void resize(int x,int y){f.resize(x,y);}
inline void shrink_to_fit(){f.shrink_to_fit();}
inline bool operator==(Poly b){return f==b.f;}
inline bool operator!=(Poly b){return f!=b.f;}
inline bool operator<(Poly b){return f<b.f;}
inline bool operator>(Poly b){return f>b.f;}
inline bool operator<=(Poly b){return f<=b.f;}
inline bool operator>=(Poly b){return f>=b.f;}
};
inline void Complete(Poly&f,int len){while(f.size()<len)f.emplace_back(0);}
inline void Init(Poly&f,int len){
int p=pw[lg[len]];
while(p<len)p<<=1;
if(len<p)Complete(f,p);
}// Complete to 2^x
inline void Cut(Poly&f,int len){while(f.size()>len)f.pop_back();}// Cut useless bits
inline void NTT(Poly&f,int t){
if(f.size()==1)return;
int n=f.size(),buf=1,G=qpow(t*(mod-1)/n);
Poly l(n>>1),r(n>>1);
for(int i=0;i<n>>1;i++)l[i]=f[i<<1],r[i]=f[i<<1|1];
NTT(l,t);NTT(r,t);
for(int i=0;i<n>>1;i++,buf=buf*G%mod){
f[i]=(l[i]+buf*r[i]%mod)%mod;
f[i+(n>>1)]=(l[i]+mod-buf*r[i]%mod)%mod;
}
}// NTT
inline Poly Convol(Poly a,Poly b){
int len=a.size()+b.size(),p=pw[lg[len]];
while(p<len)p<<=1;
Complete(a,p);NTT(a,1);
Complete(b,p);NTT(b,1);
for(int i=0;i<p;i++)a[i]=a[i]*b[i]%mod;
NTT(a,-1);
for(int i=0;i<p;i++)a[i]=a[i]*inv[p]%mod;
while(a.back()==0)a.pop_back();
return a;
}// Convolution
inline Poly Inverse(Poly f){
Init(f,f.size());
if(f.size()==1)return Poly(1,qpow(f[0],mod-2));
int n=f.size(),p=pw[lg[n]];
Poly hlf(n>>1);
for(int i=0;i<n>>1;i++)hlf[i]=f[i];
Poly g=Inverse(hlf);
while(p<n<<1)p<<=1;
Complete(f,p);NTT(f,1);
Complete(g,p);NTT(g,1);
for(int i=0;i<p;i++)g[i]=(2+mod-f[i]*g[i]%mod)%mod*g[i]%mod;
NTT(g,-1);
for(int i=n;i<p;i++)g[i]=0;
for(int i=0;i<p;i++)g[i]=g[i]*inv[p]%mod;
return g;
}// Inverse
inline Poly operator*(Poly a,Poly b){return Poly(Convol(a.f,b.f));}
}
using namespace Polynomial;// call Init() before use
int n,m,q,T,lim,a[N],A[N][N];
vector<Poly>vec;Poly tmp(2),G(0),F(0);
struct Young{
#define mid ((l+r)>>1)
int table[325][M],type;
void Apply(int u,int val){
table[u][++table[u][0]]=val;
if(type==0&&u<=T)a[u]++;
if(type==1&&table[u][0]>T)a[table[u][0]]++;
}
void Insert(int u,int val){
if(u>T)return;
int l=1,r=table[u][0]+1,res=r;
while(l<=r)((table[u][mid]>val)^type)?res=mid,r=mid-1:l=mid+1;
if(res>table[u][0])return Apply(u,val);
swap(val,table[u][res]);Insert(u+1,val);
}
}young[2];
Poly Divide(int l,int r){return l==r?vec[l]:(Divide(l,mid)*Divide(mid+1,r));}
int Gauss(int n){
int res=1,op=1;
for(int i=1,p=0;i<=n;i++,p=0){
for(int j=i;j<=n&&!p;j++)if(A[j][i])p=j;
if(i!=p)swap(A[i],A[p]),op*=-1;
for(int j=i+1;j<=n;j++)
for(int k=i,coef=A[j][i]*qpow(A[i][i],mod-2)%mod;k<=n;k++)
add(A[j][k],mod-A[i][k]*coef%mod);
}
for(int i=1;i<=n;i++)(res*=A[i][i])%=mod;
return(mod+res*op)%mod;
}
signed main(){
//file("startrek-bonus-2");
young[0].type=0;young[1].type=1;
n=read();m=read();q=read();T=sqrt(n);Init();
for(int i=1,p;i<=n;i++)young[0].Insert(1,p=read()),young[1].Insert(1,p);
for(int i=1;i<=(n=q);i++)lim=max(lim,a[i]+n);
for(int i=1;i<=m;i++)tmp[0]=1,tmp[1]=mod-read(),vec.emplace_back(tmp);
Init(G=Divide(0,m-1),lim+1);F=Inverse(G);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[j]+i>=j)A[i][j]=F[a[j]+i-j];
printf("%lld\n",Gauss(n));
return 0;
}
T2调了两小时,烦死了
頑張って