【超好懂的比赛题解】2020ICPC澳门站 个人题解
title : 2021ICPC澳门站 个人题解
date : 2022-10-6
tags : ACM,题解,练习记录
author : Linno
2020ICPC澳门站 个人题解
题目链接:https://codeforces.com/gym/103119
补题进度:8/12
A-Accelerator
这是一个自己卷自己的分治FFT模板,复杂度为 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
#define rep(i,x,y) for(int i=x;i<=y;++i)
#define repd(i,x,y) for(int i=x;i>=y;--i)
using namespace std;
const int N=1e6+7;
const int mod=998244353;int t,n,m,a[N];
int lim,L,G=3,rev[N];
int f[N<<1],g[N<<1],h[N<<1],inv[N<<1],frac[N<<1],ifrac[N<<1];int read(){ int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}inline int fpow(int a,int b){int res=1;while(b){if(b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}return res;
}void NTT(int *A,int limit,int type){for(int i=0;i<limit;++i) if(i<rev[i]) swap(A[i],A[rev[i]]);for(int mid=1;mid<limit;mid<<=1){int wn=fpow(G,(mod-1)/(mid<<1));for(int pos=0;pos<limit;pos+=(mid<<1)){int w=1;for(int k=0;k<mid;k++,w=1ll*w*wn%mod){int x=A[pos+k],y=1ll*w*A[pos+mid+k]%mod;A[pos+k]=(x+y)%mod;A[pos+k+mid]=(x-y+mod)%mod; }}}if(type==1) return;for(int i=1;i<limit/2;++i) swap(A[i],A[limit-i]);int inv=fpow(limit,mod-2);for(int i=0;i<limit;++i) A[i]=1ll*A[i]*inv%mod;
}void NTT_mul(int *f,int *g,int *h,int n,int m){int lim=1,L=0;while(lim<=n+m) lim<<=1,L++;for(int i=n+1;i<lim;++i) f[i]=0;for(int i=m+1;i<lim;++i) g[i]=0;for(int i=0;i<lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));NTT(f,lim,1);NTT(g,lim,1);for(int i=0;i<lim;++i) h[i]=1ll*f[i]*g[i]%mod;NTT(h,lim,-1);
}vector<int>solve(int l,int r){vector<int>res;if(l==r) return {1,a[l]};int mid=((l+r)>>1);int len1=(mid-l+1),len2=r-mid;auto res1=solve(l,mid);auto res2=solve(mid+1,r);for(int i=0;i<=len1;++i) f[i]=res1[i];for(int i=0;i<=len2;++i) g[i]=res2[i];NTT_mul(f,g,h,len1,len2);res.resize(len1+len2+1);for(int i=0;i<len1+len2+1;++i) res[i]=h[i];return res;
}signed main(){inv[0]=inv[1]=1;for(int i=2;i<N;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;frac[0]=ifrac[0]=1;for(int i=1;i<N;++i){frac[i]=1ll*frac[i-1]*i%mod;ifrac[i]=1ll*ifrac[i-1]*inv[i]%mod;}t=read();while(t--){n=read();for(int i=1;i<=n;++i) a[i]=read();auto res=solve(1,n);int ans=0;for(int i=1;i<=n;++i){ans+=1ll*res[i]*frac[i]%mod*frac[n-i]%mod;if(ans>=mod) ans-=mod; }ans=1ll*ans*ifrac[n]%mod;write(ans);putchar('\n');}return 0;
}
C-Club Assignment
从高位到低位,将0和1分到不同的集合,如果有超过3个是相同的数位,就对答案没有贡献,直接分治到下一层。对于长度为4以下的区间可以直接暴力枚举两边异或最小值最大的方案,然后向上合并即可。
#include<bits/stdc++.h>
#define mk make_pair
#define pii pair<int,int>
#define F first
#define S second
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int N=3e5+7;pii a[N];
int t,n,ans[N];ll solve(int l,int r,int pos){ //求从pos位向下分[l,r]区间可得到的答案 if(r-l+1==1){ //只有一个数的集合直接返回ans[a[l].S]=1;return inf;}else if(r-l+1<=4){ //如果区间长度在4以内直接枚举 if(r-l+1==2){ans[a[l].S]=1;ans[a[r].S]=2;return inf;}vector<pii>s1,s2;ll mx=0;for(int i=l;i<=r;++i){for(int j=i+1;j<=r;++j){vector<pii>A,B;A.push_back(a[i]);A.push_back(a[j]);for(int k=l;k<=r;++k){ //将a[i],a[j]放在A集合,其他放在B集合 if(k==i||k==j) continue;B.push_back(a[k]);}ll va=inf,vb=inf;va=A.front().F^A.back().F;if(B.size()>1) vb=B.front().F^B.back().F;if(min(va,vb)>=mx){ //替换原来的答案 s1=move(A);s2=move(B);mx=min(va,vb);}}}for(auto p:s1) ans[p.S]=1;for(auto p:s2) ans[p.S]=2;return mx;}if(pos<0){if(r-l+1>=3){for(int i=l;i<=r;++i) ans[a[i].S]=1;return 0;}if(r-l+1==2){ans[a[l].S]=1;ans[a[r].S]=2;}else ans[a[l].S]=1;return inf;}int p=l;while(p<=r){//如果有两个以上在这一位上是1,那么就等于失效了,找下一位,否则将左右分到不同集合 if((a[p].F&(1<<pos))) break;++p;}ll mi=inf;if(p>l) mi=min(mi,solve(l,p-1,pos-1));if(p<=r) mi=min(mi,solve(p,r,pos-1));return mi;
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>t;while(t--){cin>>n;for(int i=1,x;i<=n;++i){cin>>x;a[i]=mk(x,i);}sort(a+1,a+1+n);cout<<solve(1,n,30)<<"\n"; for(int i=1;i<=n;++i) cout<<ans[i];cout<<"\n";}return 0;
}
D-Artifacts
签到题,队友getline写完的,用Python写了一遍发现真的好写。
import sys
import mathatk=0.0
ar=0.0
cr=5.0
cdr=50.0
for i in range(5):for j in range(5):str=input()if(str[0]=='A'):if(str[4]=='R'):tmp=float(str.split('+')[-1].split('%')[0])ar+=tmpelse:tmp=float(str.split('+')[-1])atk+=tmpelif(str[0]=='C'):if(str[5]=='R'):tmp=float(str.split('+')[-1].split('%')[0])cr+=tmpelse:tmp=float(str.split('+')[-1].split('%')[0])cdr+=tmp
if(cr>100):cr=100
atk=(1500.0)*(1+ar/100.0)+atk
ans=atk*(1.0-cr/100.0)+atk*(1.0+cdr/100.0)*(cr/100.0)
print(ans)
F-Fixing Networks
① n < c ∗ ( d + 1 ) n<c*(d+1) n<c∗(d+1),即上述方式抽不出c个团。
② d 是奇数且 n 是奇数 d是奇数且n是奇数 d是奇数且n是奇数,那么最后会剩出一个奇环,环上不可能每个点不能连奇数个点。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int n,d,c;
vector<int>ans[N];signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>d>>c;if(n<(d+1)*c||((d&1)&&(n&1))){cout<<"No\n";return 0;}else if(d==0){if(c==n) cout<<"Yes\n";else cout<<"No\n";return 0;}else if(d==1){if(2*c==n){cout<<"Yes\n";for(int i=1;i<=n;++i) cout<<(i+((i&1)?1:-1))<<"\n";}else cout<<"No\n";}else{int L=1;for(int p=1;p<=c-1;p++,L+=d+1){ //c-1团 int R=L+d;for(int i=L;i<=R;++i){for(int j=L;j<=R;++j){if(i!=j) ans[i].emplace_back(j); }}}if(L<=n){ //剩下[L~n]的点int len=n-L+1; //这里有一个环if((len&1)&&(d&1)){cout<<"No\n";return 0;}for(int i=L;i<=n;++i){for(int j=1;j<=d/2;++j){ans[i].emplace_back(L+(i-L+j+len)%len);}for(int j=1;j<=d/2;++j){ans[i].emplace_back(L+(i-L-j+len)%len);}if(d&1){int tmp=i+len/2;if(tmp>n) tmp-=len;ans[i].emplace_back(tmp);}}}cout<<"Yes\n";for(int i=1;i<=n;++i){stable_sort(ans[i].begin(),ans[i].end());for(auto j:ans[i]) cout<<j<<" ";cout<<"\n";\}}return 0;
}
G-Game on Sequence
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+7,M=300;
int n,m,a[N],lst[M],sg[M];bool cmp(int A,int B){return lst[A]>lst[B];
}inline void work(){memset(sg,1,sizeof(sg));vector<int>tmp;for(int i=0;i<M;++i) if(lst[i]) tmp.emplace_back(i);sort(tmp.begin(),tmp.end(),cmp);for(auto num:tmp){bool flag=false;for(int i=0;i<8;++i){if(!sg[num^(1<<i)]){flag=1;break;}}if(flag) sg[num]=1;else sg[num]=0;}
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=n;++i) cin>>a[i],lst[a[i]]=i;work();for(int i=1,op,x;i<=m;++i){cin>>op>>x;if(op==1){a[++n]=x;lst[a[n]]=n;work();}else{if(lst[a[x]]==x){if(sg[a[x]]) cout<<"Grammy\n";else cout<<"Alice\n";}else cout<<"Grammy\n";}}return 0;
}
I-Nim Cheater
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=20001;int ans[N],fa[N],val[N],cost[N];
vector<int>G[N];
int sz;
bool hson[N];int dfs(int p){ //重链剖分 int cnt=1,mx=0,son=-1;for(int to:G[p]){int res=dfs(to);if(res>mx){mx=res;son=to;}cnt+=res;}if(son>=0) hson[son]=1;return cnt;
}int res[N];
void solve(int p,int tot){ //树上dp,先遍历轻儿子,然后遍历重儿子 int *bk;if(!hson[p]){bk = new int[N];for(int i=0;i<N;++i) bk[i]=res[i];}for(int i=0;i<N;++i){res[i^val[p]]=min(res[i^val[p]],res[i]+cost[p]);}ans[p]=res[tot^val[p]];int son=-1;for(int to:G[p]){if(hson[to]){son=to;continue;}solve(to,tot^val[p]);}if(son>=0) solve(son,tot^val[p]);if(!hson[p]){for(int i=0;i<N;++i) res[i]=bk[i];delete [] bk;}
}int num;
void printans(int p){if(!num) return;if(p){cout<<ans[p]<<"\n";num--;}for(int to:G[p]){if(!num) return;printans(to);if(!num) return;cout<<ans[p]<<"\n";num--;}
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int n,cur=0;cin>>n;string op;for(int i=1;i<=n;++i){ //所有操作可以构成一棵树 cin>>op;if(op=="ADD"){++sz;cin>>val[sz]>>cost[sz];G[cur].emplace_back(sz);fa[sz]=cur;cur=sz;}else{cur=fa[cur];}}memset(res,inf,sizeof(res));res[0]=0;dfs(0);solve(0,0);num=n;printans(0);return 0;
}
J-Jewel Grab
#include<bits/stdc++.h>
#define inf 1e12
using namespace std;
typedef long long ll;
const int N=2e5+7;int n,m,c[N],pre[N],nxt[N],lst[N];
ll v[N],mvc[N];
set<int>pos[N]; struct Nod{ //线段树上结点记录区间的权值和以及最右边的颜色前驱 int l,r,mx;ll s;
}tr[N<<2];
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((tr[p].l+tr[p].r)>>1)void pushup(int p){tr[p].mx=max(tr[ls].mx,tr[rs].mx);tr[p].s=tr[ls].s+tr[rs].s;
}void build(int p,int l,int r){tr[p].l=l;tr[p].r=r;if(l==r){tr[p].mx=pre[l];tr[p].s=v[l];return;}build(ls,l,mid);build(rs,mid+1,r);pushup(p);
}void modify(int p,int pos){if(tr[p].l==tr[p].r){tr[p].mx=pre[tr[p].l];tr[p].s=v[tr[p].l];return;}if(pos<=mid) modify(ls,pos);else modify(rs,pos);pushup(p);
}ll query(int p,int ql,int qr){ if(ql<=tr[p].l&&tr[p].r<=qr) return tr[p].s;ll res=0;if(ql<=mid) res=query(ls,ql,qr);if(qr>mid) res+=query(rs,ql,qr);return res;
}int find(int p,int st,int k){ //找第一个前驱在st之后的结点if(tr[p].l==tr[p].r) return tr[p].l;int pos=-1;if(tr[ls].mx>=st&&k<=mid) pos=find(ls,st,k);if(pos!=-1) return pos;if(tr[rs].mx>=st) pos=find(rs,st,k);return pos;
}signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=n;++i){cin>>c[i]>>v[i];pos[c[i]].insert(i);pre[i]=lst[c[i]];lst[c[i]]=i;}for(int i=n;i>=1;--i) if(pre[i]) nxt[pre[i]]=i;build(1,1,n);for(int i=1,op,x,y,k;i<=m;++i){cin>>op;if(op==1){ //对于修改操作而言,就是在链表和线段树上单点修改 cin>>x>>y>>k;pos[c[x]].erase(x);if(lst[c[x]]==x) lst[c[x]]=pre[x];c[x]=y;v[x]=k;if(nxt[x]){if(pre[x]){nxt[pre[x]]=nxt[x];pre[nxt[x]]=pre[x];modify(1,nxt[x]);}else{pre[nxt[x]]=0;modify(1,nxt[x]);}}else{if(pre[x]) nxt[pre[x]]=0; }int p;auto it=pos[y].lower_bound(x);if(it==pos[y].end()){nxt[x]=-1;pre[x]=lst[y];if(pre[x]!=-1) nxt[pre[x]]=x;modify(1,x);}else{p=*it;if(pre[p]){nxt[pre[p]]=x;pre[x]=pre[p];modify(1,x);}else{pre[x]=0;modify(1,x);}nxt[x]=p;pre[p]=x;modify(1,p);}pos[y].insert(x);lst[y]=max(lst[y],x);}else{vector<int>col;col.clear();cin>>x>>k;int cur=x;ll ans=0;for(int j=0;j<=k&&cur<=n;++j){ //筛选k个前缀在s之前的结点 int p=find(1,x,cur);if(p==-1){ans+=query(1,cur,n); //如果没有颜色重复 break;}else{col.emplace_back(c[p]);if(j<k){if(mvc[c[p]]==0) mvc[c[p]]=v[pre[p]];if(v[p]>mvc[c[p]]){ //记录该颜色经过筛选后的最大权值 ans-=mvc[c[p]];ans+=v[p];mvc[c[p]]=v[p];}}ans+=query(1,cur,p-1);cur=p+1;for(auto u:col) mvc[u]=0;}}cout<<ans<<"\n";}}return 0;
}
L-Random Permutation
推出来的式子是 n ! ∗ n ! n n \frac{n!*n!}{n^n} nnn!∗n!
import sys
import mathn=int(input())
ans=math.factorial(n)*math.factorial(n)/(n**n)
print(ans)
【超好懂的比赛题解】2020ICPC澳门站 个人题解相关推荐
- 【超好懂的比赛题解】HNCPC Multi-university Training Round3 比赛题解
title : HNCPC Multi-university Training Round3 date : 2022-7-29 tags :ACM,练习记录 author : LINNO HNCPC ...
- 【超好懂的比赛题解】第十八届同济大学程序设计竞赛暨高校网络友谊赛
title : 第十八届同济大学程序设计竞赛暨高校网络友谊赛 date : 2022-5-30 tags : ACM,题解,练习记录 author : Linno 第十八届同济大学程序设计竞赛暨高校网 ...
- 【超好懂的比赛题解】“山大地纬杯”第十二届山东省ICPC大学生程序设计竞赛(正式赛)
title : "山大地纬杯"第十二届山东省ICPC大学生程序设计竞赛(正式赛) date : 2022-5-30 tags : ACM,题解,练习记录 author : Linn ...
- 2021ICPC澳门站部分题解
链接 A 构造一个生成函数就完了,正好有一个板子,贴一下完事.社会主义重拳出击,没想到区域赛会出这种题.澳门的前六个题是签到.模拟.最小异或生成树.分治ntt.构造.dag上sg函数.跪了.和大陆的区 ...
- 马走日-深搜回溯-超好懂题解
马在中国象棋以日字形规则移动. 请编写一段程序,给定n*m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点. Input 第一行为整数T ...
- 【ICPC 2022 澳门站】A题 So I‘ll Max Out My Constructive Algor... 题解
题目大意 给定一个 n ∗ n n*n n∗n的数字矩阵,代表每个点的高度,每个数各不相同,求一条遍历所有的点的路径,要求只能上下左右移动,且高度下降的次数不小于高度上升次数. 题目链接 思路 事实上 ...
- REVA世界巡回交流会——亚太峰会 澳门站拉开序幕
数字金融界最近有不少大事发生,世界知名数字平台REVA举办世界巡回交流会,其中亚太地区第一站选在澳门,2023年5月8日至10日期间,将盛大举行此次高峰论坛,REVA管理高层悉数到场,行业内外精英齐聚 ...
- 2020ICPC沈阳站后记
沈阳站金的很意外,去的时候我们三个人根本就没有抱着打金的心态,就像hl学长赛后说的那样,之前心里想着冲金拼的时候总也是银首,今天压根就没想,结果反而金了. 略详细得回顾一下这次沈阳之行赛中赛外各种细节 ...
- 第45届ICPC沈阳站部分题解(D、F、G、H、I、J、K)
文章目录 D-前缀和思想+dfs F-贪心 G H-双指针+dp 题意 思路 代码 I-追及问题+裴蜀定理 J-可持久化线段树 K-前缀和+积分的定义 题意 思路 参考链接 传送门 本文CSDN 本文 ...
最新文章
- 其他算法-高斯白噪声
- - 运算符(C# 参考)
- css3实现烟花效果,CSS3 带颤动效果的简易烟花动效
- BootStrap之前奏响应式布局
- python实训内容_Python实验课:Python元组数据及其运算
- TensorFlow和Keras解决大数据量内存溢出问题
- 查询所有_学会DSUM函数,轻松搞定所有的数据查询与数据求和
- 怎么把手机录音转换成mp3?
- WIN10打印机显示服务器脱机,网络打印机脱机,教你win10网络打印机脱机无法打印的应对办法...
- cisco思科交换机恢复出厂设置清除配置的方法
- PPT画图如何保存600dpi以及消除白边问题
- 高中计算机二级考试试题,高中二年级全国计算机等级考试试题.doc
- 十五天学会Autodesk Inventor,看完这一系列就够了(一),前言—介绍及区别
- 关于寻找海王id的算法伪代码分析思路
- 1. CUDA安装失败解决方法
- BCGSoft BCGControlBar for .NET托管代码工具包
- OpenCV 之视频文件的处理
- 多个目标优化的帕累托前沿面如何可视化
- OR青年导师访谈特辑 | 香港理工大学助理教授 马玮:一次拉长的面试 一个交流的平台
- c语言浮点数值显示两位,C语言中,输出浮点数时保留两位小数应该怎么搞?