Codeforces Round 966 (Div. 3)

A - Primary Task

给一个数 \(x\le 10000\),判断其是否形如 \(\overline{ab}\) 满足 \(a=10,b\ge 2\) 且无前导零。

模拟判断即可。

code
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+3;
int T;
string n;
void solve(){
	cin>>n;
	if((n=="1"||n=="101"||n=="10"||n=="100"||n=="1000"||n=="10000")||n.size()==1||n[0]!='1'||n[1]!='0'||n[2]=='0'){
		cout<<"No\n";
	}else{
		cout<<"Yes\n";
	}
}
signed main(){
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

B - Seating in a Bus

车上有 \(n\) 个座位,有 \(n\) 个人要上车,判断这 \(n\) 个人上车顺序是否合法:

  • \(i=1\) 合法;
  • 若座位 \(a_i-1\)\(a_i+1\) 不为空则合法,否则不合法;
  • 若合法则 \(i\) 在座位 \(a_i\) 坐下。

同样边模拟边判断即可。

code
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+3;
int T;
int n;
int a[maxn];
int b[maxn];
void solve(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		if(i==1) b[a[i]]=1;
		else{
			if(b[a[i]-1]||b[a[i]+1]) b[a[i]]=1;
			else{
				cout<<"NO\n";
				return;
			}
		}
	}
	cout<<"YES\n";
}
signed main(){
	cin>>T;
	while(T--){
		solve();
		for(int i=1;i<=n;i++) b[a[i]]=0;
	}
	return 0;
}

C - Numeric String Template

给一个数字串 \(a\) 以及一个字符串 \(s\),判断 \(s\) 是否为模板串

模板串定义:

  • \(|s|=n\)
  • 对于每一个相同的 \(s_i\) 有唯一的 \(a_i\)(值)与其匹配
  • 对于每一个相同的 \(a_i\) 有唯一的 \(s_i\)(值)与其匹配

\(n\le 2\times 10^5,|a_i|\le 2\times 10^9\)

唐氏。没看见 \(a_i\) 可以为 0(你CF的 pretest 也太水了罢我去),被 hack 了。

在遍历 \(s\) 的时候,分类讨论:

  • \(s_i\) 未出现过:若 \(a_i\) 对应了另一个字符,则 \(s\) 不是模板串;
  • \(s_i\) 出现过:若 \(a_i\) 对应了另一个字符,或者 \(s_i\) 对应了另一个值,则 \(s\) 不是模板串。

开两个 map 判断即可,注意要么使用 .count(a[i]/s[i])要么初值要赋值为绝对值大于 \(2\times 10^9\) 的数!!

code
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+3;
int T;
int n;
int a[maxn];
int b[26];
map<int,bool>mp;
void ss(){
	string s;
	cin>>s;
	if(s.size()!=n){
		cout<<"NO\n";
		return;
	}
	for(int i=1;i<=n;i++){
		if(b[s[i-1]-'a']==INT_MAX){
			if(mp[a[i]]){
				cout<<"NO\n";
				return;
			}
			mp[a[i]]=1;
			b[s[i-1]-'a']=a[i];
			
		} 
		else{
			if(b[s[i-1]-'a']!=a[i]){
				cout<<"NO\n";
				return;
			}
		}
	}
	cout<<"YES\n";
	
}
void solve(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	int t;
	cin>>t;
	while(t--){
		ss();
		for(int i=0;i<26;i++) b[i]=INT_MAX;
		mp.clear();
	}
}
signed main(){
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

D - Right Left Wrong

给你一个长为 \(n\) 的数列 \(a(a_i> 0)\) 和 LR 串 \(s\)

进行任意次操作:

  • 选择两个位置 \(l,r\) 满足 \(s_l=\texttt{L},s_r=\texttt{R}\),将答案加上 \(a_{[l,r]}\) 的和,并将 \(s_{[l,r]}\) 置为 \(\texttt{.}\)

求得到的最大答案。

考虑贪心地取最左边的 L 和最右边的 R,这样得到的和一定是最大的(实际操作顺序是从里到外)。

code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=3e5+3;
int T;
int n;
int a[maxn],pre[maxn];
char s[maxn];
void solve(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		pre[i]=pre[i-1]+a[i];
	}
	cin>>s;
	int l=0,r=strlen(s)-1,ans=0;
	while(l<r){
		while(l<r&&s[l]!='L') l++;
		while(l<r&&s[r]!='R') r--;
		if(l<r){
			ans+=pre[r+1]-pre[l];
			l++,r--;
		}
	}
	cout<<ans<<'\n';
}
signed main(){
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

E - Photoshoot for Gorillas

给你一个 \(n\times m\) 的网格,另有 \(w\) 个猩猩,权值为 \(a_i\),将所有将猩猩放入不同的网格中,总得分为每个 \(k\times k\) 的子网格的权值之和,求最大得分。

\(w\le n\times m\le 2\times 10^5,k\le \min(n,m)\)

首先考虑将 \(a\) 排序,然后将最大值放到被最多子网格覆盖的地方,依此类推。

对于每个格子 \((i,j)\),其被覆盖次数的计算公式为 \(\min(i,n-i+1,k,n-k+1)*\min(j,m-j+1,k,m-k+1)\),这个画图理解即可。

时间复杂度 \(O(mn+w)\)

code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=3e5+3;
int T;
int n,m,ans,k,w;
int a[maxn];
int stk[maxn],top;
void solve(){
	ans=0;
	top=0;
	cin>>n>>m>>k;
	cin>>w;
	for(int i=1;i<=w;i++){
		cin>>a[i];
	}
	sort(a+1,a+w+1,greater<int>());
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			int t=(min(min(i,n-i+1),min(k,n-k+1)))*(min(min(j,m-j+1),min(k,m-k+1)));
			stk[++top]=t;
		}
	}
	sort(stk+1,stk+top+1,greater<int>());
	for(int i=1;i<=w;i++){
		ans+=stk[i]*a[i];
	}
	cout<<ans<<'\n';
}
signed main(){
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

F - Color Rows and Columns

给你 \(n\)\(a_i\times b_i\) 的矩阵,每次你可以选择一个矩阵并填充一个格子,当你每填满一行或一列格子时,得分加一,求到达 \(k\) 分的最少操作次数。

\(n\le 1000,a_i,b_i,k\le 100\)

容易发现每个操作的顺序不重要,每个矩阵的得分是独立的,设 \(g_{i,k}\) 为在第 \(i\) 个矩阵中,得到 \(k\) 分的最小操作次数。

这可以贪心去求,每次填充较短的一变即可。注意当剩余一个格子时,填充会得到两分,即无法得到 \(2(a_i+b_i)-1\) 分。

剩下的就是背包问题了,设 \(f_{i,k}\) 表示目前在背包 \(i\),获得了 \(k\) 分的最小操作次数,则有转移:

\[f_{i,k}=\min\limits_{j=0}^{k}(f_{i-1,k-j}+g_{i,j}) \]

再次注意,由于我们得不到 \(2(a_i+b_i)-1\) 分,所以可能最后实际得分大于 \(k\),所以答案需要在 \(f_{n,[k,k+n]}\) 之间取个 \(\min\)

时间复杂度 \(O(n(k+\sum (a_i+b_i)))\)

code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000+3;
const int maxk=1100+3;
int T;
int n,k;

set<int>s;
priority_queue<int>q[maxk<<1];
int a[maxn],b[maxn];
int g[maxn][maxk],cnt[maxn];
int f[maxn][maxk];// 到 i,旋了 j 个
void ss(int i,int x,int y){
	cnt[i]=0;g[i][0]=0;
	while(x){
		if(x>y) swap(x,y);
		if(!x) break;
		++cnt[i];
		g[i][cnt[i]]=g[i][cnt[i]-1]+x;
		y--;
	}
	cnt[i]++;
	g[i][cnt[i]]=g[i][cnt[i]-1];
	g[i][cnt[i]-1]=0x3f3f3f3f;
}
void solve(){
	cin>>n>>k;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=k+n;j++)
			f[i][j]=g[i][j]=0x3f3f3f3f;
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i],ss(i,a[i],b[i]);
	for(int i=1;i<=k+n;i++) f[1][i]=g[1][i];
	for(int i=2;i<=n;i++){
		for(int j=1;j<=k+n;j++){
			for(int l=0;l<=j;l++){
				f[i][j]=min(f[i][j],f[i-1][j-l]+g[i][l]);
			}
		}
	}
    int ans=0x3f3f3f3f;
    for(int i=k;i<=n+k;i++) ans=min(ans,f[n][i]);
    if(ans==0x3f3f3f3f) cout<<"-1\n";
    else cout<<ans<<'\n';
}
signed main(){
	cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

G - Call During the Journey

H - Ksyusha and the Loaded Set

posted @ 2024-08-14 17:26  view3937  阅读(129)  评论(0编辑  收藏  举报
Title