2024noip模拟赛终结篇

vandan 了,最后一场了!

A 【模板】分治FFT

考虑只有 3 堆水果的情况,设有 a,b,c,则按一定顺序合并的答案是 a×b+(a+b)×c=ab+bc+ac。可以发现所有情况答案一样。那我们只需要模拟一次合并再乘以方案数即可。

考虑第一次合并,n 个数里任选两个,且前后没有顺序,方案数是 (n2)

然后,把合并好的那一堆看成一个,递推上面的过程,发现每一次合并都会使堆总数减一,那么方案数就是 (i2)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5,mod=998244353;
int n,a;
inline int getc(int n)
{
return n*(n-1)%mod*499122177%mod;
}
signed main()
{
freopen("fft.in","r",stdin);
freopen("fft.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>a;
int ans=0,sum=a;
for(int i=2;i<=n;i++)
{
cin>>a;
ans=(ans+(sum*a)%mod)%mod;
sum=(sum+a)%mod;
}
for(int i=n;i>1;i--) ans=(ans*getc(i))%mod;
cout<<ans;
}

B 【模板】最近公共祖先

考虑是一棵树时的构造,一定是从下往上选,如果遇到 sizu 大于 1 的情况,就让儿子互相连边,如果剩下一个就传给连向 u 父亲的边。

这样答案就是 m2,构造很成立。

然后如果有非树边,传给父亲等着连。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int T;
int n,m;
const int N=3e5+5;
vector<int>e[N];
struct node{
int x,y,z;
};
int siz[N],fa[N];
bitset<N>vis;//whether the chain from father to it has been chosen
vector<node>ans{};
int lst[N],ins[N];
queue<int>q;
void dfs(int u)
{
vis[u]=ins[u]=1;
for(int v:e[u])
{
if(!vis[v])dfs(v);
}
for(int v:e[u])
{
if(ins[v]) continue;
if(lst[v]) ans.push_back({u,v,lst[v]}),lst[v]=0;
else q.push(v);
}
while(q.size()>=2)
{
int x=q.front();q.pop();
int y=q.front();q.pop();
ans.push_back({x,u,y});
}
if(!q.empty())
{
int x=q.front();q.pop();
lst[u]=x;
}
ins[u]=0;
}
void Q()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=n;i++)if(!vis[i])
dfs(i);
cout<<ans.size()<<"\n";
for(node i:ans) cout<<i.x<<" "<<i.y<<" "<<i.z<<"\n";
}
signed main()
{
freopen("lca.in","r",stdin);
freopen("lca.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
T=1;
while(T--)Q();
}

C 【模板】普通平衡树

n2 我会。

dp[i][1/0] 表示当前在 1,上一个数小于(大于)ai 的最大长度,直接转移即可。

可以发现当 n>2 时,最长锯齿子序列长度 =2+ 满足 (aiai1)×(ai+1ai)<0i 的个数。可以用线段树对每个子段维护左端和右端情况,和 i 的个数,然后 pushdown 传下去,查到叶子即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,q;
inline int sgn(int x)
{
return (x>0)?1:-1;
}
struct node{
int len,ans,cl,cr,wl,wr;
}tr[N<<2];
inline node operator+(node A,node B)
{
if(!A.len)return B;
if(!B.len)return A;
if(A.len==1 && B.len==1)
{
int tmp=sgn(B.wl-A.wl);
return (node){2,2,tmp,tmp,A.wl,B.wl};
}
if(A.len==1)
{
int tmp=sgn(B.wl-A.wr);
return (node){1+B.len,B.ans+(tmp!=B.cl),tmp,B.cr,A.wl,B.wr};
}
if(B.len==1)
{
int tmp=sgn(B.wl-A.wr);
return (node){1+A.len,A.ans+(tmp!=A.cr),A.cl,tmp,A.wl,B.wr};
}
int tmp=sgn(B.wl-A.wr);
int add=(tmp!=A.cr)+(tmp!=B.cl);
return (node){A.len+B.len,A.ans+B.ans-(2-add),A.cl,B.cr,A.wl,B.wr};
}
struct SegTree{
#define lid now<<1
#define rid now<<1|1
void pushdown(int now)
{
tr[lid]=(tr[lid]+tr[now]),tr[rid]=(tr[rid]+tr[now]);
tr[now]={0,0,0,0,0,0};
}
void modify(int now,int l,int r,int x,int y,node w)
{
if(x<=l&&r<=y)
{
tr[now]=(tr[now]+w);
return ;
}int mid=(l+r)>>1;pushdown(now);
if(x<=mid) modify(lid,l,mid,x,y,w);
if(y>mid) modify(rid,mid+1,r,x,y,w);
}
int query(int now,int l,int r,int x)
{
if(l==r) return tr[now].ans;
int mid=(l+r)>>1;pushdown(now);
if(x<=mid) return query(lid,l,mid,x);
else return query(rid,mid+1,r,x);
}
}st;
signed main()
{
freopen("odt.in","r",stdin);
freopen("odt.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>q;
while(q--)
{
int op;
cin>>op;
if(op==1)
{
int l,r,x;cin>>l>>r>>x;
st.modify(1,1,n,l,r,{1,1,0,0,x,x});
}
else
{
int x;cin>>x;
cout<<st.query(1,1,n,x)<<"\n";
}
}
}

D 【模板】平面最近点对

上场先开 T4,写了俩小时二分答案写假了。。。

最后还不如人家暴力分高。

posted @   ccjjxx  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示