题解:AtCoder Beginner Contest 367
总体情况

A - Shout Everyday
题意
在 AtCoder 王国,居民们每天都要在 \(A\) 点大声喊出他们对章鱼烧的热爱。
住在 AtCoder 王国的高桥每天 \(B\) 点睡觉, \(C\) 点起床( \(24\) 小时钟)。他醒着的时候可以喊出对章鱼烧的爱,但睡着的时候却不能。判断他是否每天都能喊出对章鱼烧的爱。这里,一天有 \(24\) 小时,他的睡眠时间小于 \(24\) 小时。
- \(0\leq A,B,C\lt 24\)
- \(A\) 、 \(B\) 和 \(C\) 成对不同。
- 所有输入值均为整数。
题解
24小时制,只要 \(b\) 或 \(c\) 比 \(a\) 小,那么直接 \(b\gets b+24\),\(c\gets c+24\)。直接比较 \(c\) 和 \(b\) 的大小即可
Code
// Problem: A - Shout Everyday
// Contest: AtCoder - AtCoder Beginner Contest 367
// URL: https://atcoder.jp/contests/abc367/tasks/abc367_a
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');};
}
void write(int x,char y){write(x);write(y);}
signed main(){
int t,a,b;
read(t);read(a);read(b);
if(t<a) t+=24;
if(b<a) b+=24;
if(b<t) puts("Yes");
else puts("No");
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
B - Cut .0
题意
一个实数 \(X\) 以及 \(x\) 的小数点后第三位。
请在以下条件下打印实数 \(X\) 。
- 小数部分不能有尾数 "0"。
- 小数点后不能有多余的尾数。
思路
前面输入一位,输出一位。遇见小数点停止。然后分别处理后三位就行。(用了十分钟,好伤心)
Code
// Problem: B - Cut .0
// Contest: AtCoder - AtCoder Beginner Contest 367
// URL: https://atcoder.jp/contests/abc367/tasks/abc367_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');};
}
void write(int x,char y){write(x);write(y);}
signed main(){
char a[200];int b;
char tmp;
tmp=getchar();
while(tmp!='.') write(tmp),tmp=getchar();
if(1){
char a = getchar();
char b = getchar();
char c = getchar();
if(a=='0'&&b=='0'&&c=='0') return 0;
write('.');
if(c!='0') write(a),write(b),write(c);
else if(b!='0') write(a),write(b);
else write(a);
}
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
C - Enumerate Sequences
题意
按升序排列打印所有满足以下条件的长度为 \(N\) 的整数序列。
- 第 \(i\) 个元素介于 \(1\) 和 \(R_i\) 之间。
- 所有元素之和是 \(K\) 的倍数。
思路
暴搜即可。
Code
// Problem: C - Enumerate Sequences
// Contest: AtCoder - AtCoder Beginner Contest 367
// URL: https://atcoder.jp/contests/abc367/tasks/abc367_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');};
}
void write(int x,char y){write(x);write(y);}
int n,k,r[10];
vector<int> num;
void dfs(int now,int sum){
if(now==n+1){
if(sum%k!=0) return;
for(int i:num){
write(i,' ');
}
write(endl);
return;
}
for(int i = 1;i<=r[now];i++){
num.push_back(i);
dfs(now+1,(sum+i)%k);
num.pop_back();
}
}
signed main(){
read(n);
read(k);
for(int i = 1;i<=n;i++){
read(r[i]);
}
dfs(1,0);
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
D - Pedometer
题意
一个湖周围有 \(N\) 个休息区。
这些休息区按顺时针顺序编号为 \(1\) 、 \(2\) 、......、 \(N\) 。
从休息区 \(i\) 顺时针走到休息区 \(i+1\) 需要 \(A_i\) 步(其中休息区 \(N+1\) 指的是休息区 \(1\) )。
从休息区 \(s\) 顺时针走到休息区 \(t\) ( \(s \neq t\) )所需的最小步数是 \(M\) 的倍数。
求 \((s,t)\) 的可能对数。
- 所有输入值均为整数
- \(2 \le N \le 2 \times 10^5\)
- \(1 \le A_i \le 10^9\)
- \(1 \le M \le 10^6\)
思路
小思维题。
我们首先可以断环为链。计算前缀和,只要一个前缀和跟另外一个前缀和模 \(m\) 相等,那么这就是一对合法的答案。于是我们可以开一个桶记录前面有多少个数模 \(m\) 的余数为 \(i\)。
记得开 long long!
Code
// Problem: D - Pedometer
// Contest: AtCoder - AtCoder Beginner Contest 367
// URL: https://atcoder.jp/contests/abc367/tasks/abc367_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');};
}
void write(int x,char y){write(x);write(y);}
const int MAXN = 4e5+10;
int n,m,a[MAXN],qzh[MAXN],ans;
map<int,int> mp;
signed main(){
read(n);read(m);
for(int i = 1;i<=n;i++){
read(a[i]);
a[i+n] = a[i];
}
for(int i = 1;i<=2*n;i++){
qzh[i] = (qzh[i-1]+a[i-1])%m;
if(i>n) --mp[qzh[i-n]];
ans += mp[qzh[i]];
if(i<=n) mp[qzh[i]]++;
}
write(ans);
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
E - Permute K times
题意
给你一个长度为 \(N\) 的序列 \(X\) ,其中每个元素都介于 \(1\) 和 \(N\) 之间(含),以及一个长度为 \(N\) 的序列 \(A\) 。
打印在 \(A\) 上执行以下操作 \(K\) 次的结果。
将 \(A_i\) 替换为\(A_{X_i}\)。每个操作同时进行。
思路
元素 \(i\) 经过 \(k\) 次变化后的值就是元素 \(X_i\) 经过 \(k-1\) 次变化后的值。
于是我们可以将 \(i\) 和 \(X_i\) 连边。很容易发现,每一个点的出度为 \(1\),这是一颗内向基环树。于是我们处理每一个点到环上的距离,如果距离比 \(k\) 小,那么直接倍增爬树,否则直接在树上转圈圈。
时间复杂度:\(O(n\log n)\)。
Code
// Problem: E - Permute K times
// Contest: AtCoder - AtCoder Beginner Contest 367
// URL: https://atcoder.jp/contests/abc367/tasks/abc367_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');};
}
void write(int x,char y){write(x);write(y);}
const int MAXN = 2e5+10;
const int LOGN = log2(MAXN)+10;
int n,k;
//DSU
int fath[MAXN];
int get_father(int x){
if(x==fath[x]) return x;
return fath[x] = get_father(fath[x]);
}
//Topo
int rd[MAXN],nxt[MAXN],ordinary[MAXN],root[MAXN];
bitset<MAXN> loop;
void Topo(){
loop.set();
queue<int> q;
for(int i = 1;i<=n;i++){
if(rd[i]==0) q.push(i);
}
while(!q.empty()){
int k = q.front();q.pop();
loop.reset(k);
if(--rd[nxt[k]]==0) q.push(nxt[k]);
}
}
//ST
int ST_fath[MAXN][LOGN],dis[MAXN],is[MAXN];
int jump(int x,int tmp){
int k = 0;
while(tmp){
if(tmp&1) x = ST_fath[x][k];
tmp>>=1;
k++;
}
return x;
}
void ST_init(){
for(int j = 1;j<LOGN;j++){
for(int i = 1;i<=n;i++){
ST_fath[i][j] = ST_fath[ST_fath[i][j-1]][j-1];
}
}
}
//Base ring tree
int find_loop(int k,int &r){
if(dis[k]) return r=root[k],dis[k];
if(loop[k]) return r=k,dis[k]=0;
ST_fath[k][0] = nxt[k];
return dis[k] = find_loop(nxt[k],root[k])+1,r=root[k],dis[k];
}
vector<int> has[MAXN];
bitset<MAXN> vis;
void dfs(int k){
if(vis[k]) return;
vis[k] = 1;
is[k] = has[get_father(k)].size();
has[get_father(k)].push_back(k);
dfs(nxt[k]);
}
signed main(){
read(n);read(k);
for(int i = 1;i<=n;i++) fath[i] = i;
for(int i = 1;i<=n;i++){
read(nxt[i]);
fath[get_father(i)] = get_father(nxt[i]);
rd[nxt[i]]++;
}
for(int i = 1;i<=n;i++){
read(ordinary[i]);
}
Topo();
for(int i = 1;i<=n;i++){
find_loop(i,root[i]);
}
for(int i = 1;i<=n;i++){
if(loop[i]){
dfs(i);
}
}
ST_init();
for(int i = 1;i<=n;i++){
if(k<dis[i]) write(ordinary[jump(i,k)],' ');
else write(ordinary[has[get_father(root[i])][(is[root[i]]+(k-dis[i]))%has[get_father(root[i])].size()]],' ');
}
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
F - Rearrange Query
题意
给你长度为 \(N\) 的正整数序列: \(A=(A_1,A_2,\ldots,A_N)\) 和 \(B=(B_1,B_2,\ldots,B_N)\) 。
给你 \(Q\) 个查询,让你按顺序处理。 \(i\) -th 查询的解释如下。
- 给定正整数 \(l_i,r_i,L_i,R_i\) 。如果可以重新排列子序列 \((A_{l_i},A_{l_i+1},\ldots,A_{r_i})\) 以匹配子序列 \((B_{L_i},B_{L_i+1},\ldots,B_{R_i})\) 则打印
Yes,否则打印No。
思路
很简单啦。
这个题非常经典,一眼哈希,于是我用了基于 mt19937_64 的异或哈希,结果:

我仔细地想了想,发现如果是这样的话,那么哈希值不就费了吗:1 2 3 5 5、1 2 3 100 100。
于是我奇思妙想地阴谋狡诈地试了试运气,加了一个前缀和判断,结果AC了!
Code
// Problem: F - Rearrange Query
// Contest: AtCoder - AtCoder Beginner Contest 367
// URL: https://atcoder.jp/contests/abc367/tasks/abc367_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
namespace gtx{
// Fast IO
void read(int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(unsigned int &x){
x = 0;int h = 1;char tmp;
do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
x*=h;
}
void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
void write(char x){putchar(x);}
void write(int x){
if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
do{st[++tot]=x%10,x/=10;} while(x);
while(tot){putchar(st[tot--]+'0');};
}
void write(int x,char y){write(x);write(y);}
const int MOD = 1000000000039;
const int MAXN = 2e5+10;
unsigned long long qzha[MAXN],qzhb[MAXN];
int qa[MAXN],qb[MAXN];
int n,q,a[MAXN],b[MAXN];
map<int,int> mp;
signed main(){
read(n);read(q);
mt19937_64 mt(time(0));
for(int i = 1;i<=n;i++){
read(qzha[i]);
mp[qzha[i]]= mt();
}
for(int i = 1;i<=n;i++){
read(qzhb[i]);
mp[qzhb[i]]= mt();
}
for(int i = 1;i<=n;i++){
qzha[i] = mp[qzha[i]];
qzhb[i] = mp[qzhb[i]];
qa[i] = qzha[i]%MOD;
qb[i] = qzhb[i]%MOD;
// cout <<qzha[i] << qzhb[i] << endl;
qzha[i] ^= qzha[i-1];
qzhb[i] ^= qzhb[i-1];
qa[i] = (qa[i]+qa[i-1])%MOD;
qb[i] = (qb[i]+qb[i-1])%MOD;
}
while(q--){
int l,r,L,R;
read(l);read(r);read(L);read(R);
if(r-l+1!=R-L+1) puts("No");else
puts((qzha[r]^qzha[l-1])==(qzhb[R]^qzhb[L-1])
&&((((qa[r]-qa[l-1])%MOD)+MOD)%MOD)==((((qb[R]-qb[L-1])%MOD)+MOD)%MOD)
?"Yes":"No");
}
return 0;
}
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
// ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T = 1;
// gtx::read(T);
while(T--) gtx::main();
return 0;
}
tag
Atcoder、ABC

浙公网安备 33010602011771号