偶然看这一场的题目,忽然很有感觉,于是写了一下

A

题面

考虑每一位可以单独分开考虑

考虑单独的一位,每次要选 \(m\) 个位置,可能产生贡献的位置就是这位为 1 的数,设数量为 \(x\),则 \(m|x\)

最后显然合法的 \(m\) 满足 \(m| \gcd_{i=0}^{29} M_i\)

记得特判全为 \(0\) 的情况

Code
  1. #include<bits/stdc++.h>
  2. #define reg register
  3. #define int long long
  4. using namespace std;
  5. inline int read(){
  6. int k=1,x=0;char ch=getchar();
  7. while (ch<'0'||ch>'9') {if (ch=='-') k=-1; ch=getchar();}
  8. while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
  9. return k*x;
  10. }
  11. inline int cmin(reg int x,reg int y){return x<y?x:y;}
  12. inline int cmax(reg int x,reg int y){return x>y?x:y;}
  13. const int N=2e5+10,INF=1e18;
  14. int n,a[N];
  15. inline int gcd(reg int x,reg int y){return y==0?x:gcd(y,x%y);}
  16. inline bool check(){for (reg int i=1;i<=n;i++) if (a[i]) return false; return true;}
  17. signed main(){reg int _=read(); while (_--){
  18. n=read();for (reg int i=1;i<=n;i++) a[i]=read();
  19. if (check()){for (reg int i=1;i<=n;i++) printf("%lld ",i);puts("");continue;}
  20. reg int d=-1;
  21. for (reg int t=0;t<=30;t++){
  22. reg int cnt=0;
  23. for (reg int i=1;i<=n;i++) if (a[i]>>t&1) cnt++;
  24. if (d<0) d=cnt; else d=gcd(d,cnt);
  25. }
  26. for (reg int i=1;i<=d;i++) if (d%i==0) printf("%lld ",i); puts("");
  27. }
  28. return 0;
  29. }

B

题面

一个直接的想法是建图跑最短路

考虑没有"下滑 \(b_i\)" 的限制应该怎么做,可以直接线段树优化建图。

考虑加入这个限制,对 \([0,n]\) 建立一个虚点,每个 \(i\) 和对应的虚点区间 \([i-a_i,i]\) 连边,然后再由虚点的 \(i\) 连向 \(i-b_i\)

使用 01bfs 优化复杂度。

Code
  1. #include<bits/stdc++.h>
  2. #define reg register
  3. #define int long long
  4. using namespace std;
  5. inline int read(){
  6. int k=1,x=0;char ch=getchar();
  7. while (ch<'0'||ch>'9') {if (ch=='-') k=-1; ch=getchar();}
  8. while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
  9. return k*x;
  10. }
  11. inline int cmin(reg int x,reg int y){return x<y?x:y;}
  12. inline int cmax(reg int x,reg int y){return x>y?x:y;}
  13. const int N=(4e5+10)*5,INF=1e18,mod=998244353;
  14. int n,a[N],b[N],idx,id[N],vis[N],pre[N],dis[N];
  15. #define mp make_pair
  16. vector<pair<int,int> > G[N];
  17. inline void add(reg int u,reg int v,reg int w){G[u].push_back(mp(v,w));}
  18. inline void build(reg int p,reg int l,reg int r){
  19. if (l==r) return (void)(id[p]=l+n+1);id[p]=++idx; reg int mid=l+r>>1;
  20. build(p<<1,l,mid),build(p<<1|1,mid+1,r); add(id[p],id[p<<1],0),add(id[p],id[p<<1|1],0);
  21. }
  22. inline void modify(reg int p,reg int l,reg int r,reg int L,reg int R,reg int node){
  23. if (L<=l&&r<=R) return add(node,id[p],1); reg int mid=l+r>>1;
  24. if (L<=mid) modify(p<<1,l,mid,L,R,node); if (R>mid) modify(p<<1|1,mid+1,r,L,R,node);
  25. }deque<int> q;
  26. signed main(){
  27. n=read(); idx=2*n+1;
  28. for (reg int i=1;i<=n;i++) a[i]=read();for (reg int i=1;i<=n;i++) b[i]=read();
  29. for (reg int i=0;i<=n;i++) add(i+n+1,i+b[i],0); build(1,0,n);
  30. for (reg int i=1;i<=n;i++) modify(1,0,n,i-a[i],i,i);
  31. memset(dis,0x3f,sizeof(dis)); dis[n]=0; q.push_back(n);
  32. while(!q.empty()){
  33. reg int u=q.front(); q.pop_front();
  34. if (vis[u]) continue; vis[u]=1;
  35. for (auto it:G[u]) if (dis[it.first]>dis[u]+it.second){ reg int v=it.first;
  36. dis[v]=dis[u]+it.second;
  37. if (!vis[v]){if (it.second) q.push_back(v); else q.push_front(v); pre[v]=u;}
  38. }
  39. }
  40. if (dis[0]>=INF) return !printf("-1");
  41. printf("%lld\n",dis[0]);
  42. vector<int> path; reg int now=0;
  43. while(now!=n){
  44. if (n+1<=now&&now<=2*n+1) path.push_back(now-n-1);
  45. now=pre[now];
  46. }
  47. reverse(path.begin(), path.end());
  48. for (auto x:path) printf("%lld ",x);
  49. return 0;
  50. }

C

题面

首先注意到一个显然的结论,b 数组插入后一定是单调不降的

所以考虑将 b 排序,然后可以分治解决

定义函数 solve(l,r,L,R) 表示 \(b_l\) 到 \(b_r\) 将插入到 \(a_L\) 到 \(a_R\) 之前

考虑枚举 \(b_{mid}\) 所在的最优位置,这个容易通过前缀和后缀操作进行维护

最后重新构建整个数组,计算一下逆序对就好了,时间复杂度是 \(\Theta(n \log n)\)级别的

Code
  1. #include<bits/stdc++.h>
  2. #define reg register
  3. #define int long long
  4. using namespace std;
  5. inline int read(){
  6. reg int k=1,x=0;char ch=getchar();
  7. while (ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();}
  8. while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
  9. return k*x;
  10. }
  11. inline int cmin(reg int x,reg int y){return x<y?x:y;}
  12. const int N=2e6+10,INF=1e18;
  13. int n,m,a[N],b[N],p[N],pre[N],suf[N],d[N],tot,d_[N],tot_;
  14. inline void solve(reg int l,reg int r,reg int L,reg int R){
  15. if (l>r) return; reg int mid=l+r>>1;
  16. pre[L]=0;for (reg int i=L+1;i<=R;i++) pre[i]=pre[i-1]+(a[i-1]>b[mid]);
  17. suf[R]=0;for (reg int i=R-1;i>=L;i--) suf[i]=suf[i+1]+(b[mid]>a[i]);
  18. p[mid]=L; for (reg int i=L+1;i<=R;i++) if (pre[p[mid]]+suf[p[mid]]>pre[i]+suf[i]) p[mid]=i;
  19. solve(l,mid-1,L,p[mid]),solve(mid+1,r,p[mid],R);
  20. }
  21. vector<int> v[N];
  22. struct BIT{
  23. int c[N];
  24. inline void clear(){for (reg int i=0;i<=tot_;i++) c[i]=0;}
  25. inline void mdf(reg int x,reg int k){for (;x;x-=x&-x) c[x]+=k;}
  26. inline int qry(reg int x){reg int res=0;for (;x<=tot_;x+=x&-x) res+=c[x];return res;}
  27. }t;
  28. inline int calc(){ tot_=tot; reg int ans=0;
  29. for (reg int i=1;i<=tot;i++) d_[i]=d[i]; sort(d_+1,d_+tot_+1);
  30. tot_=unique(d_+1,d_+tot_+1)-d_-1;
  31. for (reg int i=1;i<=tot;i++) d[i]=lower_bound(d_+1,d_+tot_+1,d[i])-d_;
  32. for (reg int i=1;i<=tot;i++){
  33. ans+=t.qry(d[i]+1); t.mdf(d[i],1);
  34. } t.clear();
  35. return ans;
  36. }
  37. signed main(){
  38. reg int _=read(); for (reg int qwq=1;qwq<=_;qwq++){
  39. n=read(),m=read(),tot=0;
  40. for (reg int i=1;i<=n;i++) a[i]=read();
  41. for (reg int i=1;i<=n+1;i++) v[i].clear();
  42. for (reg int i=1;i<=m;i++) b[i]=read(); sort(b+1,b+m+1); solve(1,m,1,n+1);
  43. for (reg int i=1;i<=m;i++) v[p[i]].push_back(b[i]);
  44. for (reg int i=1;i<=n+1;i++){
  45. for (auto it:v[i]) d[++tot]=it; if (i<=n) d[++tot]=a[i];
  46. }
  47. printf("%lld\n",calc());
  48. }
  49. return 0;
  50. }

D

题面

巧妙的贪心

考虑将输入按照 \(\max\{s,a\}\) 为第一关键字,\(s\) 为第二关键字排序

考虑这个贪心的正确性:

  • \(\max\{s_{i+1},a_{i+1}=s_{i+1}\}\):即 \(i+1\) 的限制更松,那么无论此时 \(i\) 把山的高度更新到多高都对 \(i+1\) 的选取不造成影响
  • \(\max\{s_{i+1},a_{i+1}=a_{i+1}\}\):即 \(i+1\) 更新后的条件更难满足,那么若 \(i+1\) 选了,\(i\) 一定不能选,那么让 \(i\) 先尝试能不能选一定不会更劣
  • 最后考虑 \(\max\{s_i,a_i\}=\max\{s_{i+1},a_{i+1}\}\) 那么一定是可以攀登的先攀登,条件更严格的先上
Code
  1. #include<bits/stdc++.h>
  2. #define reg register
  3. #define int long long
  4. using namespace std;
  5. inline int read(){
  6. reg int k=1,x=0;char ch=getchar();
  7. while (ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();}
  8. while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
  9. return k*x;
  10. }
  11. inline int cmin(reg int x,reg int y){return x<y?x:y;}
  12. inline int cmax(reg int x,reg int y){return x>y?x:y;}
  13. const int N=2e6+10,INF=1e18;
  14. int n,m,ans;
  15. struct Node{
  16. int s,a;
  17. inline bool operator<(const Node &rhs)const{return cmax(s,a)<cmax(rhs.s,rhs.a)||cmax(s,a)==cmax(rhs.s,rhs.a)&&s<rhs.s;}
  18. }p[N];
  19. signed main(){
  20. n=read(),m=read(); for (reg int i=1;i<=n;i++) p[i].s=read(),p[i].a=read(); sort(p+1,p+n+1);
  21. for (reg int i=1;i<=n;i++) if (p[i].s>=m) ans++,m=cmax(m,p[i].a); printf("%lld",ans);
  22. return 0;
  23. }

E

题面

首先一个贪心:对于一个询问的答案为

\[\sum_{i=l+kx}^r \min_{j=l}^i a_i
\]

也就是一个前缀最小的前缀和

发现最后答案的段数与 \(r\) 没有太大的关系,考虑将询问按照 \(l \bmod k\) 分类,此时的 \(r\) 应更改为 \(l+\lfloor {r-l\over k} \rfloor k\)

之后考虑怎么处理不同起点前缀最小值,这是很经典问题,可以从后忘前单调栈处理。将 \(\bmod k\) 与 \(l\) 的位置提出为关键点,关键点之前再加入区间最小值 \(\min_{i=l+kx+1}^{l+k(x+1)-1} a_i\)

最后二分出 \(r\) 在单调栈哪个位置之后,前面的部分可以用前缀和处理得到

实现时要小心

Code
  1. #include<bits/stdc++.h>
  2. #define reg register
  3. #define int long long
  4. using namespace std;
  5. inline int read(){
  6. reg int k=1,x=0;char ch=getchar();
  7. while (ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();}
  8. while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
  9. return k*x;
  10. }
  11. inline int cmin(reg int x,reg int y){return x<y?x:y;}
  12. inline int cmax(reg int x,reg int y){return x>y?x:y;}
  13. const int N=2e6+10,INF=1e18;
  14. int n,m,k,ans[N],st[N][20],lg[N],a[N];
  15. struct Node{int l,r,id;inline bool operator<(const Node &rhs){return r<rhs.r;}}p[N];
  16. vector<Node> v[N];
  17. inline int chkmin(reg int x,reg int y){return a[x]<a[y]?x:y;}
  18. inline int query(reg int l,reg int r){reg int len=lg[r-l+1];return chkmin(st[l][len],st[r-(1<<len)+1][len]);}
  19. int cnt,b[N],s[N],top,sum[N];
  20. inline int ask(reg int l,reg int r){if (l>r) return 0; return sum[r]-sum[l-1];}
  21. inline int calc(reg int l,reg int r,reg int x){
  22. reg int posl=l/k*k+x,posr=r/k*k+x; if (posl<l) posl+=k; if (posr>r) posr-=k;
  23. if (posl>posr) return 0; return (posr-posl)/k+1;
  24. }
  25. signed main(){
  26. n=read(),m=read(),k=read(); lg[0]=-1;
  27. for (reg int i=1;i<=n;i++) st[i][0]=i,a[i]=read(),lg[i]=lg[i>>1]+1;
  28. for (reg int i=1;i<=m;i++) p[i].l=read(),p[i].r=p[i].l+(read()-p[i].l)/k*k,p[i].id=i,v[p[i].l].push_back(p[i]);
  29. for (reg int j=1;(1<<j)<=n;j++) for (reg int i=1;i+(1<<j)-1<=n;i++) st[i][j]=chkmin(st[i][j-1],st[i+(1<<j-1)][j-1]);
  30. for (reg int d=1;d<=k;d++){ top=cnt=0;
  31. for (reg int i=d;i<=n;i+=k){ b[++cnt]=i; reg int tmp;
  32. if (i+1<=cmin(i+k,n)-1) tmp=query(i+1,cmin(i+k,n)-1),b[++cnt]=tmp;
  33. }
  34. for (reg int i=cnt;i>=1;i--){
  35. while (top&&a[b[i]]<=a[s[top]]) top--; s[++top]=b[i];
  36. sum[top]=sum[top-1]+calc(s[top],s[top-1]-1,d%k)*a[s[top]];
  37. if (b[i]%k==d%k) for (auto it:v[b[i]]){
  38. reg int l=1,r=top,pos;
  39. while (l<=r){reg int mid=l+r>>1; s[mid]<=it.r?pos=mid,r=mid-1:l=mid+1;}
  40. ans[it.id]=sum[top]-sum[pos]+a[s[pos]]*calc(s[pos],it.r,d%k);
  41. }
  42. }
  43. }for (reg int i=1;i<=m;i++) printf("%lld\n",ans[i]);
  44. return 0;
  45. }

F

题面

发现如果 \(n \le 10^6\) 是简单的,考虑折半搜索

首先转化一下答案,定义 \(b_i\) 为 \(i\) 的字典序,答案为 \(\sum_{i=1}^n b_i-i\)

我们将一个数 \(x\) 拆成 \(\overline{pq}\)

那么一个数的贡献就是 \(b_{\overline{p000000}}-\overline{p000000}+b_{q}-q\)

发现与 \(q\) 有关的计算是容易的,可以暴力地预处理

之后再枚举 \(p\),对于所有可能的 \(p\),对于 \(\overline{p000000}-\overline{p999999}\) 都合法且暴力的 \(p\) 用前缀和维护一下

复杂度为 \(\Theta(\sqrt n \log \sqrt n)\)

Code
  1. #include<bits/stdc++.h>
  2. #define reg register
  3. #define int long long
  4. using namespace std;
  5. inline int read(){
  6. reg int k=1,x=0;char ch=getchar();
  7. while (ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();}
  8. while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
  9. return k*x;
  10. }
  11. inline int cmin(reg int x,reg int y){return x<y?x:y;}
  12. inline int cmax(reg int x,reg int y){return x>y?x:y;}
  13. const int N=2e6+10,Mod=1e9+7,mod=998244353,B=1000000;
  14. int n,idx,ans,sum[10];
  15. vector<int> v[10];
  16. inline int MOD(reg int x){return (x%mod+mod)%mod;}
  17. inline void dfs1(reg int x,reg int len){
  18. ++idx,v[len].push_back(MOD(idx-x)); (sum[len]+=v[len].back())%=Mod;
  19. if (len==6) return; for (reg int i=0;i<10;i++) dfs1(x*10+i,len+1);
  20. }
  21. inline void dfs2(reg int x){ if (x>n) return;
  22. if (x*B+(B-1)<=n&&x*B*10>n){ reg int now=idx;
  23. for (reg int i=0,mul=1;i<=6;i++,mul=mul*10){ reg int sz=v[i].size();
  24. reg int d=MOD(now-x*mul),pos=lower_bound(v[i].begin(),v[i].end(),mod-d)-v[i].begin();
  25. ans=(ans+d*sz+sum[i]-mod*(sz-pos))%Mod; idx+=sz;
  26. } return;
  27. }idx++;ans=(ans+MOD(idx-x))%Mod;
  28. for (reg int i=0;i<10;i++) dfs2(x*10+i);
  29. }
  30. signed main(){
  31. n=read(); dfs1(0,0); for (reg int i=0;i<=6;i++) sort(v[i].begin(),v[i].end());
  32. idx=0; for (reg int i=1;i<=9;i++) dfs2(i); printf("%lld",(ans+Mod)%Mod);
  33. return 0;
  34. }

CF1601 题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. csp-s2022游记

    ## 10.29### 民间数据:洛谷 $95+85+60+44=284$  infoj $90+40+40+44=214$  **输麻了**### 赛时经历开考前发现前面坐着 Qiuly,好可怕.开 ...

  2. vue页面中展示markdown以及katex公式

    场景 数据库中有markdown语法的字符串,需要展示为正常的页面,难点在于其中的katex数学公式 解决方式 使用showdown及其族系插件 npm i showdown npm i showdo ...

  3. selenium IDE插件的配置使用

    开头 Selenium提供了一个可以自动录制脚本的插件 叫selenium IDE 让我们一起看看如何安装使用 安装 因为google扩展商城大多数人用不了,所以我们选用的是edag来下载seleni ...

  4. java线程池和多线程的使用详解

    Java 多线程和线程池使用 java多线程实现的几种方法 1.继承Thread类 继承Thread类,重写run方法,创建线程类对象调用start方法启动线程. public class Threa ...

  5. 2022-02-01:粉刷房子 II。 假如有一排房子,共 n 个,每个房子可以被粉刷成 k 种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。 当然,因为市场上不同颜色油漆的价

    2022-02-01:粉刷房子 II. 假如有一排房子,共 n 个,每个房子可以被粉刷成 k 种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同. 当然,因为市场上不同颜色油漆的价 ...

  6. 2021-05-29:最常使用的K个单词II。在实时数据流中找到最常使用的k个单词,实现TopK类中的三个方法: Top

    2021-05-29:最常使用的K个单词II.在实时数据流中找到最常使用的k个单词,实现TopK类中的三个方法: TopK(k), 构造方法.add(word),增加一个新单词.topk(),得到当前 ...

  7. 2022-01-04:一个无序数组长度为n,所有数字都不一样,并且值都在[0...n-1]范围上。 返回让这个无序数组变成有序数组的最小交换次数。 来自小红书。

    2022-01-04:一个无序数组长度为n,所有数字都不一样,并且值都在[0-n-1]范围上. 返回让这个无序数组变成有序数组的最小交换次数. 来自小红书. 答案2022-01-04: 下标循环怼. ...

  8. flutter填坑之旅(widget原理篇)

    Flutter 的跨平台思路快速让他成为"新贵",连跨平台界的老大哥 "JS" 语言都"视而不见",大胆的选择 Dart 也让 Flutte ...

  9. 代码随想录算法训练营Day15 二叉树| 层序遍历 10 226.翻转二叉树 101.对称二叉树 2

    代码随想录算法训练营 代码随想录算法训练营Day15 二叉树| 层序遍历 10 226.翻转二叉树 101.对称二叉树 2 层序遍历10 题目链接:层序遍历10 给你二叉树的根节点 root ,返回其 ...

  10. C++面试八股文:C++中指针、引用、解引用和取地址有什么不同?

    某日小二参加XXX科技公司的C++工程师开发岗位2面: 面试官:指针.引用.解引用和取地址是C++中的重要概念,请问它们在语法和语义上有所不同? 小二:指针是一个变量,它存储了一个内存地址. 小二:引 ...