隐藏页面特效

Codeforces Round 942 (Div. 1)

1|0Preface


你们有没有这样的懒狗啊,4/30打的比赛拖到5/8才来写博客,再拖下去感觉题意都要忘个精光了

这场刚好因为去了武汉,因此全队订了一个三人间,外接大脑直接Div1出四题,狠狠地之前犯病调回紫的号打了回去

后面有空一直在琢磨D的做法,最后也是想到了通过断掉环上的一条边来得到一个很简单的讨论做法,不过比赛的时候肯定没时间写的说


2|0A. Permutation Counting


不难发现最优的序列一定先是某个排列,然后将这个排列一直循环重复放

最后一定是某些数出现了k次,剩下的数出现了k+1次,直接二分找到最大的k即可

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define int long long #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; const int N=500005; int t,n,k,a[N]; signed main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%lld",&t);t;--t) { RI i; for (scanf("%lld%lld",&n,&k),i=1;i<=n;++i) scanf("%lld",&a[i]); auto check=[&](CI lim) { int cur=0; for (RI i=1;i<=n;++i) cur+=max(0LL,lim-a[i]); return cur<=k; }; int l=1,r=2e12,ret=0,mid; while (l<=r) if (check(mid=l+r>>1)) ret=mid,l=mid+1; else r=mid-1; if (ret==0) { puts("0"); continue; } for (i=1;i<=n;++i) if (a[i]<ret) k-=(ret-a[i]),a[i]=ret; sort(a+1,a+n+1,greater <int>()); for (i=1;i<=n;++i) if (a[i]==a[n]&&k>0) --k,++a[i]; int ans=n*a[n]-(n-1); for (i=1;i<=n;++i) if (a[i]!=a[n]) ++ans; printf("%lld\n",ans); } return 0; }

3|0B1. Reverse Card (Easy Version)


手玩一下式子会发现a必须是b的倍数,不妨设a=kb,此时gcd(a,b)=b

化一下式子会发现此时的限制就是b(k+1),直接枚举b的值计算即可

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; int t,n,m; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { LL ans=0; scanf("%d%d",&n,&m); for (RI b=1;b<=m&&1LL*b*(b-1)<=n;++b) if (ans+=1LL*(n+b)/(1LL*b*b),b==1) --ans; printf("%lld\n",ans); } return 0; }

4|0B2. Reverse Card (Hard Version)


看到gcd,经典的套路就是直接枚举它的值,不妨设g=gcd(a,b),则a=p×g,b=q×g,且p,q互质

那么此时的限制变为了(p+q)×gq×g2,即(p+q)q×g

p,q互质可以推出(p+q),q一定也互质,那么上面的式子成立当且仅当(p+q)g

不妨设g=k×(p+q),则a=k×(p2+pq),b=k×(pq+q2),显然pn,qm,因此可以直接枚举

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; const int N=2e6+5; int t,n,m; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { scanf("%d%d",&n,&m); LL ans=min(n,m)/2LL; for (RI p=1;p*p<=n;++p) for (RI q=1;q*q<=m;++q) { if (p==q||__gcd(p,q)!=1) continue; int x=p*(p+q),y=q*(p+q); ans+=min(n/x,m/y); } printf("%lld\n",ans); //for (RI a=1;a<=n;++a) for (RI b=1;b<=m;++b) //if ((b*gcd(a,b))%(a+b)==0&&a%b!=0&&b%a!=0) printf("a = %lld; b = %lld\n",a,b); } return 0; }

5|0C. Fenwick Tree


首先要观察到位置i上的数会产生贡献的永远是那log个位置

而如果我们单独把这些位置拿出来看,会发现ai对它们的贡献形如这样

第一轮是1,1,1,1,1,;第二轮是1,2,3,4,5,;第三轮是1,3,6,10,15,;第四轮是1,4,10,20,35……

不难看出这玩意就是个高阶前缀和,本来以为只能用矩乘爆艹的,但后面徐神一指点发现就是个傻逼组合数

虽然组合数的下标k109的,但由于上标的范围只有20,因此还是可以暴力计算

最后实现的时候注意预处理一下小范围每个数的逆元,不然复杂度会变成三个log原地升天

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; typedef vector <vector <int>> Matrix; const int N=200005,mod=998244353; inline int sum(CI x,CI y) { return x+y>=mod?x+y-mod:x+y; } inline int sub(CI x,CI y) { return x-y<0?x-y+mod:x-y; } inline int quick_pow(int x,int p=mod-2,int mul=1) { for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul; } int t,n,k,inv[35],a[N],b[N]; inline void init(CI n) { for (RI i=1;i<=n;++i) inv[i]=quick_pow(i); inv[0]=1; } inline int C(int n,int m,int ret=1) { for (RI i=1;i<=m;++i) ret=1LL*ret*(n-i+1)%mod*inv[i]%mod; return ret; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t),init(30);t;--t) { RI i,j,s; for (scanf("%d%d",&n,&k),i=1;i<=n;++i) scanf("%d",&b[i]); auto lowbit=[&](CI x) { return x&(-x); }; for (i=1;i<=n;++i) { a[i]=b[i]; for (j=i,s=0;j<=n;j+=lowbit(j),++s) b[j]=sub(b[j],1LL*a[i]*C(k-1+s,s)%mod); } for (i=1;i<=n;++i) printf("%d%c",a[i]," \n"[i==n]); } return 0; }

6|0D. Long Way to be Non-decreasing


很好的一个题,本来以为是个大力数据结构,但后面发现其实动点脑子后是个很自然很好写的题

首先由于这个操作很神秘,每次选择一个子集感觉根本难以维护,用DP之类的方法也完全不知道怎么设计状态

那么不妨考虑对于这类单调不降问题的通法:按序贪心

考虑从前往后依次确定每个数的值,在大于前一个数的基础上让该数尽量小

但是现在又有问题就是我们很难求出从某个数变到另一个数的最小步数,使得上述贪心难以实现

不过越是看起来无解的问题实际上越简单,事实上我们只需要在外层加一个二分答案,把最优化问题转化为判定性问题即可

因此现在的难点在于,给定x y k,快速回答数x能否在k次变换之内变成y

注意给出的图是一个基环内向森林,这种图不太好直接转化为有根树处理,因此我们不妨把它变成外向森林后把询问的两个点调换一下即可

因此对于每个连通块,其实无非两种情况,要么是个有根树,要么是个基环外向树

前者的情况很好判断,一个点能否在k步内到达另一个点只要判断下是否是祖先关系,然后深度差是否k即可

后者本来以为是要分每个点在/不在环上讨论的,但这样实在过于繁琐

经典的处理方法就是断掉基环树上的一条边uv,分xy经过/不经过这条边来讨论

不经过的情况和树同理,而经过的情况画个图手玩一下也很容易得到贡献的计算方式(因为v一定是树的根节点,因此可以少判很多情况)

总复杂度O((n+m)logm)

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; const int N=1e6+5,INF=1e9; int t,n,m,a[N],b[N],fa[N],dep[N],L[N],R[N],U[N],V[N],idx; vector <int> v[N]; class FileInputOutput { private: static const int S=1<<21; #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++) char Fin[S],*A,*B; public: Tp inline void read(T& x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc())); } #undef tc }F; inline int getfa(CI x) { return fa[x]!=x?fa[x]=getfa(fa[x]):x; } inline void DFS(CI now,CI fa=0) { L[now]=++idx; for (auto to:v[now]) if (to!=fa) dep[to]=dep[now]+1,DFS(to,now); R[now]=idx; } inline int ask(CI y,CI x) { if (getfa(x)!=getfa(y)) return INF; int id=getfa(x),res=INF; if (L[x]<=L[y]&&L[y]<=R[x]) res=min(res,dep[y]-dep[x]); if (L[x]<=L[U[id]]&&L[U[id]]<=R[x]) res=min(res,dep[U[id]]-dep[x]+1+dep[y]); return res; } inline bool check(CI k) { int p=1; for (RI i=1;i<=n;++i) { while (p<=m&&ask(a[i],p)>k) ++p; if (p>m) return 0; } return 1; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (F.read(t);t;--t) { RI i; for (F.read(n),F.read(m),i=1;i<=n;++i) F.read(a[i]); for (i=1;i<=m;++i) F.read(b[i]),fa[i]=i,v[i].clear(); for (i=1;i<=m;++i) { if (getfa(i)==getfa(b[i])) U[getfa(i)]=b[i],V[getfa(i)]=i; else fa[getfa(i)]=getfa(b[i]),v[b[i]].push_back(i); } for (i=1;i<=m;++i) if (i==V[getfa(i)]) idx=dep[i]=0,DFS(i); int l=0,r=m,mid,ret=-1; while (l<=r) if (check(mid=l+r>>1)) ret=mid,r=mid-1; else l=mid+1; printf("%d\n",ret); } return 0; }

7|0Postscript


被徐神上强度了,以后CF不能摆烂不打了的说,不然下次比赛又要开演了


__EOF__

本文作者hl666
本文链接https://www.cnblogs.com/cjjsb/p/18180725.html
关于博主:复活的ACM新生,目前爱好仅剩Gal/HBR/雀魂/单机/OSU
版权声明:转载请注明出处
声援博主:欢迎加QQ:2649020702来DD我
posted @   空気力学の詩  阅读(207)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2019-05-08 Luogu P5349 幂
2019-05-08 Luogu P5351 Ruri Loves Maschera
2018-05-08 CODE[VS] 1159 最大全0子矩阵
2018-05-08 关于树链剖分的一些算法
2018-05-08 Luogu P3373 【模板】线段树 2
2018-05-08 EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)
点击右上角即可分享
微信分享提示