problem C \Large problem\ C problem C
不算太复杂。
每次记录上一次关机的时间 lastlastlast,当青木在 aia_iai 来过时,如果 last+100<ailast+100<a_ilast+100<ai,则答案加上 ai−(last+100)a_i-(last+100)ai−(last+100),否则不做任何处理。
当 n=0n=0n=0 时记得特判。
cpp
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
int a[300005];
int main(){
int n,t;
cin>>n>>t;
for(int i=1;i<=n;i++)cin>>a[i];
if(n==0){//一次都没有来过,特判
cout<<t;
return 0;
}
int ans=a[1];
int las=a[1];//记录上次关机时间
a[n+1]=t;
for(int i=2;i<=n+1;i++){
if(las+100<a[i]){
ans+=a[i]-las-100;
las=a[i];
}
}
cout<<ans;
return 0;
}
problem D \Large problem\ D problem D
赛时没过QWQ。
题意:给一个矩阵,每一列都有一颗棋子,每次可以挑一个棋子向上移动一格,要求所有相邻的棋子行编号差的绝对值不超过 111,求最小操作次数。
每个棋子都对左右两边相邻的棋子有约束,如果一个棋子 iii 可能的高度是 fif_ifi,那么它左边的棋子 i−1i-1i−1 的最低可能的高度就是 min(fi−1,fi+1)\min(f_{i-1},f_i+1)min(fi−1,fi+1),同样的,它右边的棋子 i+1i+1i+1 的最低可能的高度就是 min(fi+1,fi+1)\min(f_{i+1},f_i+1)min(fi+1,fi+1)。
因此我们正着循环一遍,每次令 fi=min(fi,fi−1+1)f_i=\min(f_i,f_{i-1}+1)fi=min(fi,fi−1+1),再倒过来循环,每次使 fi=min(fi,fi+1+1)f_i=\min(f_i,f_{i+1}+1)fi=min(fi,fi+1+1),最后得到的 fff 就是能使答案最小且满足条件的解,它与原数组的差之和就是要操作的次数。
代码:
cpp
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
ll a[300005];
ll b[300005];
void solve(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=a[i];
}
ll ans=0;
for(int i=2;i<=n;i++)b[i]=min(b[i-1]+1,b[i]);
for(int i=n-1;i>=1;i--)b[i]=min(b[i+1]+1,b[i]);
for(int i=1;i<=n;i++)ans+=a[i]-b[i];//差之和就是答案
cout<<ans<<endl;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
solve();
}
return 0;
}
problem E \Large problem\ E problem E
光顾着想 D 了,E都没看。
借鉴了一位大佬的思路,orz。
题意:你站在一个地图的指定点处,每次可以向左上,正上或右上方移动一格,如果这个格子是墙,且这一列这个格子下方没有墙,就可以将这个墙清除,问对于第一行每一个点是否能到达。
观察清除墙的规则,可以发现,如果到达一列最下方的或以下,一直往上走,那么这一列所有的墙都可以被清空,换句话说,第 jjj 列最后一个障碍在第 kkk 行,且当前到达了 (i,j)(i,j)(i,j) 且 i≥ki\ge ki≥k,那么第 jjj 列的所有障碍都可以被无视,相当于第 jjj 列被打通了。
记录每一列的打通情况,广搜可以解决。
cpp
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
char a[3005][3005];
bool vis[3005][3005];
//记录是否到达过
int ope[3005],las[3005];
// ope记录打通情况,las表示每一列的最后一个障碍
int dx[4]={-1,-1,-1};
int dy[4]={-1,0,1};//增量数组减少码量
void solve(){
int n,c;
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
for(int i=1;i<=n;i++){
ope[i]=las[i]=0;
for(int j=1;j<=n;j++)vis[i][j]=0;
}//多组数据记得清空
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]=='#')
las[j]=max(las[j],i);
queue<pair<int,int> > q;
q.push({n,c});
vis[n][c]=1;
ope[c]=1;
while(q.size()){
int x=q.front().first;
int y=q.front().second;
q.pop();
for(int i=0;i<3;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||xx>n||yy<1||yy>n||vis[xx][yy])continue;
if(a[xx][yy]=='#'&&!ope[yy]&&xx<las[yy])continue;
if(xx>=las[yy])ope[yy]=1;
vis[xx][yy]=1;
q.push({xx,yy});
}
}
for(int i=1;i<=n;i++)cout<<vis[1][i];
cout<<endl;
return;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
solve();
}
return 0;
}