abc392 题解合集
草忘写了,赶紧补档。
E
这种题都能被放到 E 了吗。
考虑最小化答案为 , 是联通块个数。
考虑构造答案,首先把能加的边加上,然后用 set 和并查集维护当前联通块集合,对于之前没加过的边,能加就加。
总体复杂度 。
#include<bits/stdc++.h>
using namespace std;
int n,m,cnt,vis[200005];
struct node{
int id,x,y;
}h[200005];
int fa[200005];
void init(){
for(int i=1;i<=n;i++) fa[i]=i;
}
int find(int x){
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
void merge(int x,int y){
x=find(x);
y=find(y);
fa[x]=y;
}
set<int> s;
vector<node> ans;
void add(int id,int x,int y){
ans.push_back((node){id,x,y});
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
init();
for(int i=1;i<=m;i++){
cin>>h[i].x>>h[i].y;
if(find(h[i].x)==find(h[i].y)) continue;
vis[i]=1;
merge(h[i].x,h[i].y);
cnt++;
}
for(int i=1;i<=n;i++){
if(find(i)==i) s.insert(i);
}
for(int i=1;i<=m && cnt<n-1;i++){
if(vis[i]) continue;
if(s.find(find(h[i].x))==s.end()) continue;
s.erase(find(h[i].x));
merge(h[i].x,*s.begin());
add(i,h[i].x,*s.begin());
cnt++;
}
cout<<ans.size()<<'\n';
for(int i=0;i<ans.size();i++){
cout<<ans[i].id<<' '<<ans[i].x<<' '<<ans[i].y<<'\n';
}
return 0;
}
F
出的还行。
考虑倒序加点,也就是按 的顺序加点。
初始把所有位置设为 ,加一个点就把这个位置设为 ,寻找位置的过程可以轻松在线段树上二分求出。
总体复杂度 。
fun fact:如果看到这个题,你没有想到 FHQ,说明你的 OI 水平有提升!
#include<bits/stdc++.h>
using namespace std;
int n,p,a[500005],b[500005];
int val[1000005],ls[1000005],rs[1000005],dcnt,rt;
void pushup(int x){
val[x]=val[ls[x]]+val[rs[x]];
}
void build(int l,int r,int &x){
x=++dcnt;
if(l==r){
val[x]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,ls[x]);
build(mid+1,r,rs[x]);
pushup(x);
}
void modify(int l,int r,int pos,int x){
if(l==r){
val[x]=0;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) modify(l,mid,pos,ls[x]);
else modify(mid+1,r,pos,rs[x]);
pushup(x);
}
int find(int l,int r,int k,int x){
if(l==r) return l;
int mid=(l+r)>>1;
if(val[ls[x]]>=k) return find(l,mid,k,ls[x]);
else return find(mid+1,r,k-val[ls[x]],rs[x]);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,n,rt);
for(int i=n;i>=1;i--){
p=find(1,n,a[i],rt);
b[p]=i;
modify(1,n,p,rt);
}
for(int i=1;i<=n;i++){
cout<<b[i]<<' ';
}
return 0;
}
G
正常题吧。
但是大家是不是都是 poly 高手啊一眼秒。
首先将这个柿子移项:
设 表示 的二元组 个数, 表示集合中 这个数是否存在,那么不难得到:
答案为:
然后上面那个柿子是 的形式,所以直接 fft。
总体复杂度 。
fan fact:有一个 saber 赛时怕贺错 fft,重敲了一遍 fft。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const double PI=acos(-1);
int n,m,k,s[1000005],ans,x,f[4000005];
struct node{
double x,y;
node(){
x=y=0;
}
node(double a,double b){
x=a,y=b;
}
node operator +(const node &a)const{
return node(x+a.x,y+a.y);
}
node operator -(const node &a)const{
return node(x-a.x,y-a.y);
}
node operator *(const node &a)const{
return node(x*a.x-y*a.y,x*a.y+y*a.x);
}
node operator /(const double a)const{
return node(x/a,y/a);
}
}a[4000005],b[4000005];
void fft(node *a,int n){
for(int i=1;i<n;i++){
if(i<f[i]) swap(a[i],a[f[i]]);
}
for(int len=2,m=1;len<=n;m=len,len<<=1){
node W=node(cos(1.0*PI/m),sin(1.0*PI/m)),w=node(1,0);
for(int l=0,r=len-1;r<=n;l+=len,r+=len){
node w0=w;
for(int i=l;i<l+m;i++){
node x=a[i]+w0*a[i+m],y=a[i]-w0*a[i+m];
a[i]=x;
a[i+m]=y;
w0=w0*W;
}
}
}
}
void solve(node *a,node *b,int n,int m){
int l=log2(n+m)+1;
int s=1<<l;
for(int i=0;i<=s;i++){
f[i]=(f[i>>1]>>1)|((i&1)<<(l-1));
}
fft(a,s);
fft(b,s);
for(int i=0;i<=s;i++){
a[i]=a[i]*b[i];
}
fft(a,s);
reverse(a+1,a+s);
for(int i=0;i<=s;i++){
a[i]=a[i]/s;
}
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>k;
n=1e6;
m=1e6;
for(int i=1;i<=k;i++){
cin>>s[i];
a[s[i]]=node(1,0);
b[s[i]]=node(1,0);
}
solve(a,b,n,m);
for(int i=1;i<=k;i++){
ans+=(int)(0.5+a[2*s[i]].x)-1;
}
cout<<ans/2;
return 0;
}
本文作者:Kenma
本文链接:https://www.cnblogs.com/Kenma/p/18707448
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步