隐藏页面特效

Codeforces Round 955 (Div. 2, with prizes from NEAR!)

1|0Preface


由于考试是真彻底结束了,但队友都还没考完,这两天没事只能VP下之前没打的比赛

这场总体感觉题好水,如果不是E想复杂了导致写了1h然后卡常卡了挺久,F看一眼就会了15min就能写完,感觉有机会2h内AK的


2|0A. Soccer


签到,贪心让原来分数高的队先得分是最优的

#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,a,b,c,d; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { scanf("%d%d%d%d",&a,&b,&c,&d); if (a>b) swap(a,b),swap(c,d); if (c>d) puts("NO"); else puts("YES"); } return 0; }

3|0B. Collatz Conjecture


我们可以先重复进行这样一个暴力过程,每次找到 x 下一个能被 y 整除的数,然后变换过去

不发现这个过程在重复 x 级别后 x 就会变成 1,剩下的部分是个 1k1 的循环,可以直接求解

#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,x,y,k; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { scanf("%d%d%d",&x,&y,&k); while (x!=1&&k) { int tar=(x/y+1)*y; if (k<tar-x) x+=k,k=0; else { k-=tar-x; x=tar; while (x%y==0) x/=y; } } if (!k) { printf("%d\n",x); continue; } printf("%d\n",1+k%(y-1)); } return 0; }

4|0C. Boring Day


拿个队列维护下当前极长的且未被选择的段,考虑当选中的值之和 l 时直接贪心地划分掉一定是最优的

同时当出现选中的值之和 >r 的情形时从队首弹出元素即可,总复杂度 O(n)

#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=200005; int t,n,l,r,a[N],q[N]; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i; for (scanf("%d%d%d",&n,&l,&r),i=1;i<=n;++i) scanf("%d",&a[i]); RI H=1,T=0; int sum=0,ans=0; for (i=1;i<=n;++i) { q[++T]=a[i]; sum+=a[i]; while (sum>r) sum-=q[H++]; if (sum>=l) ++ans,sum=0,H=1,T=0; } printf("%d\n",ans); } return 0; }

5|0D. Beauty of the mountains


很显然的一个题,不妨令 diff 为初始时两种贡献的差值的绝对值

对于每个 k×k 的子矩阵,可以用二维前缀和求出它内部两种颜色的差值 ci,不难发现每个子矩阵造成的贡献一定是 ci 的倍数

由裴蜀定理,设 g=gcd(ci),则有解的充要条件为 gdiff,模拟上述过程即可

#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=505; int t,n,m,k,a[N][N],s[N][N]; char c[N][N]; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i,j; scanf("%d%d%d",&n,&m,&k); LL diff=0; for (i=1;i<=n;++i) for (j=1;j<=m;++j) scanf("%d",&a[i][j]); for (i=1;i<=n;++i) scanf("%s",c[i]+1); for (i=1;i<=n;++i) for (j=1;j<=m;++j) { s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+(c[i][j]=='1'?1:-1); if (c[i][j]=='1') diff+=a[i][j]; else diff-=a[i][j]; } if (diff==0) { puts("YES"); continue; } diff=abs(diff); int g=0; for (i=1;i+k-1<=n;++i) for (j=1;j+k-1<=m;++j) { int tmp=s[i+k-1][j+k-1]-s[i-1][j+k-1]-s[i+k-1][j-1]+s[i-1][j-1]; tmp=abs(tmp); g=__gcd(g,tmp); } if (g==0) puts("NO"); else puts(diff%g?"NO":"YES"); } return 0; }

6|0E. Number of k-good subarrays


感觉我又把简单题做复杂了,没去写数位DP去写了个很神秘的东西,最后常数还贼大卡了半天,只能说不愧是我

首先不难想到倍增,假设之前求出了 [0,2m1] 中,贡献为 0,1,2,,k 的答案

则后面一段 [2m,2m+11] 内部的 贡献为 0,1,2,,k 的答案后可以直接拿来用,剩下的就是考虑左端点在 [0,2m1] 中,右端点在 [2m,2m+11] 中的贡献了

不妨直接枚举计算贡献 i 的方案数,最后差分计算具体的方案数即可

这个问题等价于在某个区间 [l,r] 中找到最小/最大的 x 满足 bit(x)>i,利用一些二进制的性质我们可以 O(k) 直接求解

最小的就是把 l 的后缀依次改成全 1;最大的就有些麻烦,需要找到 r 中所有 0 出现的位置然后把低位填成 1;这部分的具体实现可以看代码

然后直接做复杂度是单组数据 O(k3) 的,但我们可以把倍增过程预处理一下得到一个 O(k3+t×k2) 的做法,卡卡常数可以通过

#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 mod=1e9+7; int t,k; LL n; array <int,61> f[65]; map <LL,array <int,61>> rst; inline void inc(int& x,CI y) { if ((x+=y)>=mod) x-=mod; } inline void dec(int& x,CI y) { if ((x-=y)<0) x+=mod; } inline int find_lst(const LL& l,const LL& r,CI k) { LL x=r; int cnt=__builtin_popcountll(x); if (cnt>k) return 0; for (RI i=0;i<60;++i) if ((x>>i)&1) { --cnt; x^=(1LL<<i); if (cnt+i>k) { x|=((1LL<<i)-1); if (x<l) return (r-l+1)%mod; else return (r-x)%mod; } } return (r-l+1)%mod; } inline int find_fst(const LL& l,const LL& r,CI k) { LL x=l; int cnt=__builtin_popcountll(x); if (cnt>k) return 0; for (RI i=0;i<60;++i) { if ((x>>i)&1) --cnt,x^=(1LL<<i); if (cnt+i+1>k) { x|=((1LL<<i+1)-1); if (x>r) return (r-l+1)%mod; else return (x-l)%mod; } } return (r-l+1)%mod; } inline void init(void) { array <int,61> v={0}; v[0]=1; f[0]=v; LL x=0; for (RI i,j=1;j<61;x=x*2+1,++j) { array <int,61> u={0}; for (u[0]=0,i=1;i<61;++i) u[i]=v[i-1]; for (i=1;i<61;++i) inc(v[i],u[i]); for (i=1;i<61;++i) u[i]=1LL*find_lst(0,x,i)*find_fst(x+1,x*2+1,i)%mod; for (i=60;i>=1;--i) dec(u[i],u[i-1]); for (i=1;i<61;++i) inc(v[i],u[i]); f[j]=v; } } inline array <int,61> solve(const LL& n) { if (rst.count(n)) return rst[n]; int k=__lg(n+1); LL x=(1LL<<k)-1; if (n==x) return rst[n]=f[k]; else { RI i; array <int,61> v=f[k],tmp=solve(n-x-1),u={0}; for (u[0]=0,i=1;i<61;++i) u[i]=tmp[i-1]; for (i=1;i<61;++i) inc(v[i],u[i]); for (i=1;i<61;++i) u[i]=1LL*find_lst(0,x,i)%mod*find_fst(x+1,n,i)%mod%mod; for (i=60;i>=1;--i) dec(u[i],u[i-1]); for (i=1;i<61;++i) inc(v[i],u[i]); return rst[n]=v; } } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t),init();t;--t) { scanf("%lld%d",&n,&k); array <int,61> tmp=solve(n-1); int ans=0; for (RI i=0;i<=k;++i) inc(ans,tmp[i]); printf("%d\n",ans); } return 0; }

7|0F. Sorting Problem Again


很丁真的一个题,我们可以大力维护出数组中所有 ai>ai+1 的位置 i 的集合 S,显然如果不存在这样的位置就说明数组有序

否则令 l=min(S),r=max(S)+1,显然要操作的区间至少得包含 [l,r],不妨令 mn=minlirai,mx=maxlirai

由于分界点的性质,[1,l1],[r+1,n] 都是单调不降的连续段,因此最后要保留的前缀/后缀就很好计算了,直接在对应的部分里二分一下即可

单点修改和区间最值查询用线段树维护,总复杂度 O(nlogn)

#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=500005,INF=1e9; int t,n,a[N],q,x,y; set <int> s; class Segment_Tree { private: int mn[N<<2],mx[N<<2]; public: #define TN CI now=1,CI l=1,CI r=n #define LS now<<1,l,mid #define RS now<<1|1,mid+1,r inline void updata(CI pos,CI mv,TN) { if (l==r) return (void)(mn[now]=mx[now]=mv); int mid=l+r>>1; if (pos<=mid) updata(pos,mv,LS); else updata(pos,mv,RS); mn[now]=min(mn[now<<1],mn[now<<1|1]); mx[now]=max(mx[now<<1],mx[now<<1|1]); } inline int query_min(CI beg,CI end,TN) { if (beg<=l&&r<=end) return mn[now]; int mid=l+r>>1,ret=INF; if (beg<=mid) ret=min(ret,query_min(beg,end,LS)); if (end>mid) ret=min(ret,query_min(beg,end,RS)); return ret; } inline int query_max(CI beg,CI end,TN) { if (beg<=l&&r<=end) return mx[now]; int mid=l+r>>1,ret=-INF; if (beg<=mid) ret=max(ret,query_max(beg,end,LS)); if (end>mid) ret=max(ret,query_max(beg,end,RS)); return ret; } #undef TN #undef LS #undef RS }SEG; inline void solve(void) { if (s.empty()) return (void)(puts("-1 -1")); int l=*s.begin(),r=*s.rbegin()+1; int mn=SEG.query_min(l,r),mx=SEG.query_max(l,r); if (mn<a[1]) l=1; else l=upper_bound(a+1,a+l,mn)-a; if (mx>a[n]) r=n; else r=lower_bound(a+r+1,a+n+1,mx)-a-1; printf("%d %d\n",l,r); } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]),SEG.updata(i,a[i]); for (s.clear(),i=1;i<n;++i) if (a[i]>a[i+1]) s.insert(i); for (solve(),scanf("%d",&q),i=1;i<=q;++i) { scanf("%d%d",&x,&y); if (x+1<=n&&a[x]>a[x+1]) s.erase(x); if (x-1>=1&&a[x-1]>a[x]) s.erase(x-1); a[x]=y; SEG.updata(x,a[x]); if (x+1<=n&&a[x]>a[x+1]) s.insert(x); if (x-1>=1&&a[x-1]>a[x]) s.insert(x-1); solve(); } } return 0; }

8|0Postscript


继之前给祁神的几何专题胡了几个题面后,徐神也找我外包字符串的题面了,感觉能编题题面的Gal库存要不足了的说


__EOF__

本文作者hl666
本文链接https://www.cnblogs.com/cjjsb/p/18280443.html
关于博主:复活的ACM新生,目前爱好仅剩Gal/HBR/雀魂/单机/OSU
版权声明:转载请注明出处
声援博主:欢迎加QQ:2649020702来DD我
posted @   空気力学の詩  阅读(244)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2018-07-02 QZEZ第一届“饭吉圆”杯程序设计竞赛
2018-07-02 Luogu P2286 [HNOI2004]宠物收养场
点击右上角即可分享
微信分享提示