link

前几天补完了某一场很早以前的div1,突然想来更博客,于是就有了这篇文章

A The Beatles

显然若起点和第一次到达的位置距离为 d ,那么经过的不同站点数为 $\frac{nk}{\gcd(d,nk)}$ 。

假设距离起点最近的快餐店是 1 ,枚举距离第一次到达的位置最近的快餐店是多少, $2^2$ 枚举起点和终点在左还是右,更新答案即可。

 #include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define ll long long using namespace std; const int N=1e5+;
int n,m,a,b; ll len,ans1,ans2; ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
inline ll get(ll x){
x<=?x+=len:;
x>len?x-=len:;
return x;
}
inline void upd(ll x){
x=len/gcd(len,x);
ans1=min(ans1,x),ans2=max(ans2,x);
}
inline void chk(ll x,ll y){
if (x>y) swap(x,y);
upd(y-x),upd(x+len-y);
} int main(){
scanf("%d%d%d%d",&n,&m,&a,&b); len=(ll)n*m;
ans1=len+,ans2=;
ll q=;
rep (i,,n){
ll p=(ll)(i-)*m+;
ll x=get(p-a),y=get(q-b); chk(x,y);
x=get(p-a),y=get(q+b); chk(x,y);
x=get(p+a),y=get(q-b); chk(x,y);
x=get(p+a),y=get(q+b); chk(x,y);
}
printf("%lld %lld\n",ans1,ans2);
return ;
}

B Lynyrd Skynyrd

相当于匹配一个环。

根据原排列可以知道每个数的后继 nxt[i] 是多少,那么在新序列里的某个位置 p ,它的下一个能匹配上的位置肯定是 nxt[a[p]] 所在的位置,显然贪心找 p 之后距离 p 最近的那个位置最优。

如果记 jump[i] 表示新序列上 i 位置后的下一个能匹配的位置,若不存在 jump[i]=n+1 。那么使用倍增可以得出 i 位置作为子序列的开头,匹配上的最小的右端点 R[i] 。

那么一个区间 [l,r] 能匹配上当且仅当存在 $i\in[l,r] , R[i]\leq r$ 。维护区间最小值即可。

 #include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define Vi vector<int> using namespace std; const int N=2e5+;
int n,m,Q,a[N],b[N],nxt[N],st[N][],R[N],lg[N]; Vi p[N]; int get_min(int x,int y){
int t=lg[y-x+];
return min(st[x][t],st[y-(<<t)+][t]);
} int main(){
scanf("%d%d%d",&n,&m,&Q);
rep (i,,n) scanf("%d",&a[i]);
rep (i,,n) nxt[a[i]]=a[i%n+];
rep (i,,m) scanf("%d",&b[i]),p[b[i]].push_back(i);
rep (i,,m){
int x=nxt[b[i]];
int t=upper_bound(p[x].begin(),p[x].end(),i)-p[x].begin();
if (t==(int)p[x].size()) st[i][]=m+; else st[i][]=p[x][t];
}
st[m+][]=m+;
rep (j,,) rep (i,,m+) st[i][j]=st[st[i][j-]][j-];
rep (i,,m){
int x=i;
for (int j=;~j;j--) if ((n-)>>j&) x=st[x][j];
R[i]=x;
}
memset(st,,sizeof(st));
rep (i,,m) st[i][]=R[i],lg[i]=i==?:lg[i>>]+;
rep (j,,)
for (int i=;i+(<<(j-))<=m;i++)
st[i][j]=min(st[i][j-],st[i+(<<(j-))][j-]);
while (Q--){
int l,r; scanf("%d%d",&l,&r);
if (get_min(l,r)<=r) putchar(''); else putchar('');
}
return ;
}

C U2

注意到一个抛物线 $y=x^2+bx+c$ 可以写成 $y-x^2=bx+c$ ,如果把平面上所有点坐标变为 $(x,y-x^2)$ ,那么就是 $y=bx+c$ ,一条直线。

一条抛物线的上侧部分也就是 $y>x^2+bx+c$ 的那部分,也就是坐标变换后的 $y>bx+c$ 。

原来的问题变为:两两点对连成的直线中,有多少直线的上部没有任何点。即求上凸壳的边数。

 #include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define ll long long using namespace std; const int N=1e5+;
int n,top; #define vec poi
struct poi{
ll x,y;
poi(ll x=,ll y=):x(x),y(y){}
friend vec operator - (vec A,vec B){return vec(A.x-B.x,A.y-B.y);}
friend ll operator ^ (vec A,vec B){return A.x*B.y-A.y*B.x;}
friend bool operator < (poi x,poi y){return x.x!=y.x?x.x<y.x:x.y<y.y;}
}a[N],stk[N]; int main(){
scanf("%d",&n);
rep (i,,n){
scanf("%lld%lld",&a[i].x,&a[i].y);
a[i].y-=a[i].x*a[i].x; }
sort(a+,a++n);
rep (i,,n){
while (top>=&&((a[i]-stk[top-])^(stk[top]-stk[top-]))<=) top--;
while (top&&a[i].x==stk[top].x) top--;
stk[++top]=a[i];
}
printf("%d\n",top-);
return ;
}

D Foreigner

看了别人的题解,学到了 $\mathcal{O}(11n)$ 的 dp 姿势。

这个序列显然是有一定规律性的。大致是这样:1,2,3,4,...,9, 10, 20,21, 30,31,32, 40,41,42,43, ..., 100,101,...,109, , 210, 300,301, ...

其实就是从 10 开始,每个数都是从 1 开始的某个序列中的数往后添加 0,1,...,9 ,并且能添上的数字个数是 0...10 循环的。

考虑求一个合法的数的 rank :

若当前数位num,记 x 为 rk[num] , y 为 num 去掉末位的 rank ,那么有 $x=9 + 55\lfloor \frac {y}{10} \rfloor + 0+1+...+y\%11-1 + num\%10+1$ 。

由于 $11|55$ ,所以 $x\%11=9 + 0+1+...+y\%11-1 + num\%10+1$ 。发现我们只需要知道去掉末位的数的 rk%11 的值即可,就可以推出加上一个数后的 rk%11的值了。

用 f[i][j] 表示现在在 i 位置, i 之前的数%11的值为 j ,可以延伸到的最右端点。记忆化搜索更加简洁易懂。

 #include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define ll long long using namespace std; const int N=1e5+;
int n,f[N][]; ll ans; char s[N]; int dfs(int x,int y){
if (x>n) return x-;
if (~f[x][y]) return f[x][y];
if (s[x]>=y) return x-;
return f[x][y]=dfs(x+,(y*(y-)/++s[x]%)%);
} int main(){
memset(f,-,sizeof(f));
scanf("%s",s+),n=strlen(s+);
rep (i,,n) s[i]-='';
rep (i,,n) if (s[i]) ans+=dfs(i+,s[i])-i+;
printf("%lld\n",ans);
return ;
}

E Pink Floyd

感觉挺神的

首先考虑没有粉色边的情况:

随便找一个点 x ,先假设 x 是答案。然后再找一个 x 无法到达的点 y ,若 $x\rightarrow y$ ,那么标记 y 为可达,否则将 y 设为答案, x 标记为可达。$\mathcal{O}(n)$ 次询问后会标记完所有的点,输出此时的答案即可。其实相当于一个不停转移答案节点的过程,感觉非常妙~

如果有了粉色的话,首先缩点,然后按照拓扑序:

先随便找一个度为 0 的 scc ,在里面随便找一个点 x 设为答案;然后找另一个还存在的度为 0 的 scc ,在里面随便找一个点 y ,询问 (x,y)。此时若 $x\rightarrow y$ ,把 y 删掉(和上面标记可达的意思差不多);否则将答案转移给 y ,把 x 删掉。注意这里如果一个 scc 里的点被删完了,就要把整个 scc 及它的出边删掉,加进来新的入度为 0 的 scc (类似 toposort )。

胡一下为什么先删度数为 0 的 scc :(很显然吗?)

原因是由于粉色边的存在,我们需要利用已有的粉色边。考虑一个状态,我们找到了 $u\rightarrow v$ ,即 $u\rightarrow v$ 无粉色路径有绿色边,但已知 $v\rightarrow u$ 有粉色路径。这个时候按照我们的算法会把 v 抛弃,将答案转移到 u 上来,但是事实上 v 有可能成为最终答案,如果擅自转移到 u 可能最终无法得出答案,找不到 v 。但是如果按照拓扑序来更新,每次都取度为拓扑序最靠前的 scc ,这样就不会出现 $u\rightarrow v$ 无粉色路径有绿色边, $v\rightarrow u$ 有粉色路径的情况,所以每次转移都是对的。

 #include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define Vi vector<int> using namespace std; const int N=1e5+;
int n,m,x[N],y[N],cnt,head[N];
int dfn[N],low[N],stk[N],bel[N],top,clk,scc,rd[N]; Vi V[N];
int q[N],Head[N]; set<int> S[N];
struct edge{int to,nxt;}e[N<<]; void adde(int *head,int x,int y){
e[++cnt].to=y; e[cnt].nxt=head[x]; head[x]=cnt;
} void tarjan(int u){
dfn[u]=low[u]=++clk; stk[++top]=u;
for (int i=head[u],v;i;i=e[i].nxt)
if (v=e[i].to,!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
} else if (!bel[v]) low[u]=min(low[u],dfn[v]);
if (dfn[u]!=low[u]) return;
++scc;
while (stk[top]!=u) V[scc].push_back(stk[top]),bel[stk[top--]]=scc;
V[scc].push_back(stk[top]),bel[stk[top--]]=scc;
} int ask(int x,int y){
printf("? %d %d\n",x,y),fflush(stdout);
scanf("%d",&x); return x;
} int main(){
scanf("%d%d",&n,&m);
rep (i,,m) scanf("%d%d",&x[i],&y[i]),adde(head,x[i],y[i]);
rep (i,,n) if (!dfn[i]) tarjan(i);
rep (i,,m)
if (bel[x[i]]!=bel[y[i]]&&!S[bel[x[i]]].count(bel[y[i]])){
adde(Head,bel[x[i]],bel[y[i]]);
rd[bel[y[i]]]++,S[bel[x[i]]].insert(bel[y[i]]);
}
int tail=;
rep (i,,scc) if (!rd[i]) q[++tail]=i;
while (tail>){
int x=V[q[]].back(),y=V[q[]].back();
if (!ask(x,y)) swap(q[],q[]);
x=q[]; V[x].pop_back();
if (V[x].empty()){
swap(q[tail],q[]),tail--;
for (int i=Head[x],v;i;i=e[i].nxt)
if (v=e[i].to,!--rd[v]) q[++tail]=v;
}
}
printf("! %d\n",V[q[]].back()),fflush(stdout);
return ;
}

Codeforces Round #549 (Div. 1) 题解的更多相关文章

  1. [题解] Codeforces Round #549 (Div. 2) B. Nirvana

    Codeforces Round #549 (Div. 2) B. Nirvana [题目描述] B. Nirvana time limit per test1 second memory limit ...

  2. Codeforces Round #549 (Div. 1)

    今天试图用typora写题解 真开心 参考 你会发现有很多都是参考的..zblzbl Codeforces Round #549 (Div. 1) 最近脑子不行啦 需要cf来缓解一下 A. The B ...

  3. Codeforces Round #182 (Div. 1)题解【ABCD】

    Codeforces Round #182 (Div. 1)题解 A题:Yaroslav and Sequence1 题意: 给你\(2*n+1\)个元素,你每次可以进行无数种操作,每次操作必须选择其 ...

  4. Codeforces Round #608 (Div. 2) 题解

    目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 ...

  5. Codeforces Round #525 (Div. 2)题解

    Codeforces Round #525 (Div. 2)题解 题解 CF1088A [Ehab and another construction problem] 依据题意枚举即可 # inclu ...

  6. Codeforces Round #528 (Div. 2)题解

    Codeforces Round #528 (Div. 2)题解 A. Right-Left Cipher 很明显这道题按题意逆序解码即可 Code: # include <bits/stdc+ ...

  7. Codeforces Round #466 (Div. 2) 题解940A 940B 940C 940D 940E 940F

    Codeforces Round #466 (Div. 2) 题解 A.Points on the line 题目大意: 给你一个数列,定义数列的权值为最大值减去最小值,问最少删除几个数,使得数列的权 ...

  8. Codeforces Round #677 (Div. 3) 题解

    Codeforces Round #677 (Div. 3) 题解 A. Boring Apartments 题目 题解 简单签到题,直接数,小于这个数的\(+10\). 代码 #include &l ...

  9. Codeforces Round #665 (Div. 2) 题解

    Codeforces Round #665 (Div. 2) 题解 写得有点晚了,估计都官方题解看完切掉了,没人看我的了qaq. 目录 Codeforces Round #665 (Div. 2) 题 ...

随机推荐

  1. MySql与对应的Java的时间类型

    MySql的时间类型有          Java中与之对应的时间类型date                                           java.sql.Date Date ...

  2. 《高性能MySQL》——第五章创建高性能索引

    1.创建索引基本语法格 在MySQL中,在已经存在的表上,可以通过ALTER TABLE语句直接为表上的一个或几个字段创建索引.基本语法格式如下: ALTER TABLE 表名 ADD [UNIQUE ...

  3. [转载]jdk环境变量配置方法

    JDK下载 在安装完jdk后,还需要对jdk的环境变量进行配置才能正常使用,下面教大家如何配置jdk环境变量: 1.右键选择 计算机→属性→高级系统设置→高级→环境变量 2.系统变量→新建 变量名:J ...

  4. the error about “no such file or directory”

    CHENYILONG Blog the error about "no such file or directory" when you get the question like ...

  5. order by 字段自动填写脚本

    新版 firefox 中的 hackbar 没有 order by 字段填写, 所以就有了这个: =begin pod sql注入中自动输出order by 的位数 =end pod sub MAIN ...

  6. js实现避免浏览器拦截弹出新页面的方法

    1 问题描述 点击button按钮,提交页面的form表单,后台执行完毕后返回参数,前台页面需要该参数实现跳转,如何实现保留该原来的页面,并在浏览器选项卡新建一个页面,且不被浏览器拦截? 2 方法及问 ...

  7. WPF UI 开源专贴

    1.ReactiveUI https://github.com/reactiveui/ReactiveUI http://www.reactiveui.net A MVVM framework tha ...

  8. 使用java如何操作elasticsearch?简单示例。

    在线API:https://www.elastic.co/guide/en/elasticsearch/client/java-api/2.4/transport-client.html教程:http ...

  9. 在Docker中运行EOS(MAC版)

    在Docker中运行EOS(MAC版) 在Docker中也可以简单快速的构建EOS.IO.笔者在Mac平台下参考官方文档躺了一次河.记录如下: 安装依赖 Docker 版本 17.05或者更高 tes ...

  10. 003_cd pushd popd三个命令的区别

    一. It depends. In zsh you can configure cd to push the old directory on the directory stack automati ...