题解: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 51 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

AtcoderABC

posted @ 2024-08-17 21:37  GuTongXing  阅读(210)  评论(0)    收藏  举报