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\) 分的最小操作次数,则有转移:
再次注意,由于我们得不到 \(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;
}