不知道是不是我打的最后一场模拟赛了,记录一下吧,总体来说还不错,虽然 \(T1\) 方案数求错爆零了,但 \(T3\) 场切了,暴力打满的话有265,希望 \(NOIP\) 时也可以不让自己遗憾吧。
A 【模板】分治FFT
考虑每加进来一个数的贡献 \(x_1*x_2+(x_1+x_2)*x_3+...=x_1*x_2+x_1*x_3+x_2*x_3+...\) 可以发现实际上不管怎么取都是每两个数相乘的和,所以直接一种方案的答案乘方案书即可,每次合并时少一堆,所以方案数是 $\sum \limits_{i=2}^{n} \dbinom{i}{2} $。
点击查看代码
#include<bits/stdc++.h>
#define int long long
const int mod=998244353;
const int maxn=1e5+10;
using namespace std;
int n,a[maxn],sum[maxn],ans,jc[maxn];int qpow(int x,int y)
{int ans=1;while(y){if(y&1) ans=ans*x%mod;x=x*x%mod;y>>=1;}return ans;
}int c(int n,int m)
{return jc[n]*qpow(jc[m],mod-2)%mod*qpow(jc[n-m],mod-2)%mod;
}signed main()
{freopen("fft.in","r",stdin);freopen("fft.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n;jc[0]=1;for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;for(int i=1;i<=n;i++) cin>>a[i];for(int i=n;i>=1;i--) sum[i]=(sum[i+1]+a[i])%mod;for(int i=1;i<=n;i++) ans=(ans+a[i]*sum[i+1]%mod)%mod;int temp=c(n,2);for(int i=1;i<=n-2;i++) temp=temp*c(n-i,2)%mod;cout<<ans*temp%mod;;return 0;
}
/*
2
100001 100002
*/
B 【模板】最近公共祖先
构造,但是我没仔细推,我觉得题解说的很好,所以直接放了
点击查看代码
#include<bits/stdc++.h>
const int maxn=3e5+10;
using namespace std;
int n,m,cnt,dep[maxn];
int head[maxn],to[maxn<<1],nxt[maxn<<1],tot;
vector<int> s[maxn],t[maxn];
bool vis[maxn];
struct lsx
{int x,y,z;
}ans[maxn];
void add(int x,int y)
{to[++tot]=y;nxt[tot]=head[x];head[x]=tot;
}
void addm(int x,int y)
{add(x,y),add(y,x);
}void lsx(int x)
{vis[x]=1;for(int i=head[x];i;i=nxt[i]){int y=to[i];if(vis[y]){if(dep[y]<dep[x]) s[x].push_back(y);}else dep[y]=dep[x]+1,lsx(y);}while(t[x].size()>1){int p=t[x].back();t[x].pop_back();ans[++cnt]={p,x,t[x].back()};t[x].pop_back();}while(t[x].size()&&s[x].size()){ans[++cnt]={t[x].back(),x,s[x].back()};s[x].pop_back(),t[x].pop_back();}for(auto i:s[x]) t[i].push_back(x);
}int main()
{freopen("lca.in","r",stdin);freopen("lca.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1,x,y;i<=m;i++)cin>>x>>y,addm(x,y);for(int i=1;i<=n;i++) if(!vis[i]) lsx(i);cout<<cnt<<'\n';for(int i=1;i<=cnt;i++) cout<<ans[i].x<<" "<<ans[i].y<<" "<<ans[i].z<<'\n';return 0;
}
/**/
C 【模板】普通平衡树
关于我题解没看懂这件事,考虑新加进来一个数的贡献,由于保证了互不相同,所以新加进来一个数它要么使序列更长,要么就是替换掉最后一个数使值域差更大,每次更改只和最后两个数的值有关,直接对每个序列维护最后两个数的值和答案即可,暴力是 \(O(nq)\) 的,考虑线段树优化这个过程,两个序列段合并时发现,答案只和两个序列段边界的两个值的关系有关,所以线段树直接维护每个序列段最前面的两个数的值,最后面的两个数的值,序列长度,序列答案即可,合并的时候直接分讨边界四个数的大小关系即可,需要特判序列长度小于等于2时的情况。
点击查看代码
#include<bits/stdc++.h>
#define lid id<<1
#define rid id<<1|1
#define mid (l+r>>1)
const int maxn=3e5+10;
using namespace std;
int n,q;
struct lsx
{int fi[3],en[3],size,ans,lazy;
}m[maxn<<2],mm;void add(int id,int x)
{if(!m[id].size){m[id].size++;m[id].fi[1]=m[id].en[1]=x;m[id].ans=1;}else if(m[id].size==1){m[id].size++;m[id].fi[2]=m[id].en[2]=x;m[id].ans=2;}else{if(m[id].en[1]>m[id].en[2]){if(x>m[id].en[2]){m[id].en[1]=m[id].en[2];m[id].en[2]=x;m[id].ans++;}else{if(m[id].size==2)m[id].fi[2]=x;m[id].en[2]=x;}}else{if(x<m[id].en[2]){m[id].en[1]=m[id].en[2];m[id].en[2]=x;m[id].ans++;}else{if(m[id].size==2)m[id].fi[2]=x;m[id].en[2]=x;}}m[id].size++;}
}void solve(int x,int id)
{mm=m[x];if(mm.size==1){add(id,mm.fi[1]);return ;}if(!m[id].size){m[id].size=mm.size;m[id].fi[1]=mm.fi[1];m[id].fi[2]=mm.fi[2];m[id].en[1]=mm.en[1];m[id].en[2]=mm.en[2];m[id].ans=mm.ans;}else if(m[id].size==1){if(mm.fi[1]<mm.fi[2]){if(m[id].fi[1]<mm.fi[1]){mm.fi[1]=m[id].fi[1];m[id].size=mm.size;m[id].fi[1]=mm.fi[1];m[id].fi[2]=mm.fi[2];m[id].en[1]=mm.en[1];m[id].en[2]=mm.en[2];m[id].ans=mm.ans;}else{mm.size++,mm.ans++;mm.fi[2]=mm.fi[1];mm.fi[1]=m[id].fi[1];m[id].size=mm.size;m[id].fi[1]=mm.fi[1];m[id].fi[2]=mm.fi[2];m[id].en[1]=mm.en[1];m[id].en[2]=mm.en[2];m[id].ans=mm.ans;}}else{if(m[id].fi[1]>mm.fi[1]){mm.fi[1]=m[id].fi[1];m[id].size=mm.size;m[id].fi[1]=mm.fi[1];m[id].fi[2]=mm.fi[2];m[id].en[1]=mm.en[1];m[id].en[2]=mm.en[2];m[id].ans=mm.ans;}else{mm.size++,mm.ans++;mm.fi[2]=mm.fi[1];mm.fi[1]=m[id].fi[1];m[id].size=mm.size;m[id].fi[1]=mm.fi[1];m[id].fi[2]=mm.fi[2];m[id].en[1]=mm.en[1];m[id].en[2]=mm.en[2];m[id].ans=mm.ans;}}}else{if(m[id].en[1]>m[id].en[2]){if(mm.fi[1]<mm.fi[2]){if(mm.size==2) mm.en[1]=min(mm.en[1],m[id].en[2]);m[id].size+=mm.size-1;m[id].ans+=mm.ans-1;m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];}else{if(m[id].en[2]<mm.fi[1]){m[id].size+=mm.size;m[id].ans+=mm.ans;m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];}else{if(mm.size==2) mm.en[1]=m[id].en[1];m[id].size+=mm.size-2;m[id].ans+=mm.ans-2;m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];}}}else{if(mm.fi[1]>mm.fi[2]){if(mm.size==2) mm.en[1]=max(mm.en[1],m[id].en[2]);m[id].size+=mm.size-1;m[id].ans+=mm.ans-1;m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];}else{if(m[id].en[2]>mm.fi[1]){m[id].size+=mm.size;m[id].ans+=mm.ans;m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];}else{if(mm.size==2) mm.en[1]=m[id].en[1];m[id].size+=mm.size-2;m[id].ans+=mm.ans-2;m[id].en[1]=mm.en[1],m[id].en[2]=mm.en[2];}}}}
}void down(int id)
{if(!m[id].lazy) return ;solve(id,lid);solve(id,rid);m[lid].lazy=m[rid].lazy=1;m[id].lazy=m[id].size=m[id].ans=m[id].fi[1]=m[id].fi[2]=m[id].en[1]=m[id].en[2]=0;
}void update(int id,int l,int r,int s,int t,int x)
{if(l>=s&&r<=t){m[id].lazy=1;add(id,x);return ;}down(id);if(mid>=s) update(lid,l,mid,s,t,x);if(mid<t) update(rid,mid+1,r,s,t,x);
}int query(int id,int l,int r,int x)
{// cout<<l<<" "<<r<<" "<<x<<endl;if(l==r) return m[id].ans;down(id);return x<=mid?query(lid,l,mid,x):query(rid,mid+1,r,x);
}int main()
{freopen("odt.in","r",stdin);freopen("odt.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>n>>q;while(q--){int op,l,r,x;cin>>op;if(op==1){cin>>l>>r>>x;update(1,1,n,l,r,x);}else{cin>>x;cout<<query(1,1,n,x)<<'\n';}}return 0;
}
/*
10 4
1 6 6 697
1 4 8 824
1 6 7 455
2 7*/