AtCoder Beginner Contest 278
A - Shift
Problem Statement
题意:给你一个长度为n的序列,让你移走前面k个后面补k个0。
Solution
思路:按照题意模拟即可。
#include<bits/stdc++.h>
using namespace std;
int a[1100];
int main()
{
int n,k;
cin>>n>>k;
k = min(k,n);
for(int i = 1;i<=n;i++)
cin>>a[i];
for(int i = k+1;i<=n;i++)
cout<<a[i]<<" ";
for(int i = n+1;i<=(n+k);i++)
cout<<0<<" ";
cout<<endl;
return 0;
}
B - Misjudge the Time
Problem Statement
题意:给你一个时间用\(H:M\)的形式,对小时很分钟拆分开看呢就是\(AB:\mathrm{CD}\)这里是24小时计时法。
我们需要做的是找出给定时间的下一个可能产生歧义的时间(包含当下时间)
比如对于图3,可能是\(21:\mathrm{03}\)\(或者\)\(20:\mathrm{13}\)都是合法时间,这样的就是有歧义的时间
Solution
思路:对于给定时刻往后枚举,去判断\(AB:\mathrm{CD}\)和\(AC:\mathrm{BD}\)是不是同时合法,是的话就是答案。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int h,m;
cin>>h>>m;
while(1)
{
int a = h/10,b = h%10;
int c = m/10,d = m%10;
//cout<<a*10+c<<" "<<b*10+d<<endl;
if((a*10+c<=23&&b*10+d<=59))
{
cout<<h<<" "<<m<<endl;
break;
}
m++;
if(m==60)
{
m = 0,h++;
if(h==24)
h = 0;
}
}
return 0;
}
C - FF
Problem Statement
题意:q个询问,每个询问给出T,A,B,
当T=1时,让A跟随B
当T=2时,让B跟随A
当T=3时,询问是否A与B相互跟随
Solution
思路:用map记录跟随关系,解决
#include<bits/stdc++.h>
using namespace std;
map<pair<int,int>,int>mp;
int main()
{
int n,q;
cin>>n>>q;
while(q--)
{
int op,a,b;
cin>>op>>a>>b;
if(op==1)
mp[{a,b}] = 1;
else if(op==2)
mp[{a,b}] = 0;
else
if(mp[{a,b}]&&mp[{b,a}])cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}
D - All Assign Point Add
Problem Statement
题意:给你一个长度为\(n\)的序列
给你\(q\)个询问,有三种类型:
- 给你\(x\),让你把x赋值给所有(就是让所有元素变成\(x\))
- 给你\(i\)和\(x\),把第\(i\)个元素假设\(x\)
- 给你\(i\),输出第\(i\)个元素的值
Solution
思路:首先直接模拟肯定不行的,我们思考一下本质是什么?
我们先用\(a[]\)记录初始序列,同时用\(map\)复制一遍,我们用\(base\)记录当前的基准值,一开始记为\(0\),之后如果有\(1\)操作\(base\)就变成相应的\(x\),同时\(map.clear\),因为之前的操作相当于清空了。总的来说就是除了一开始的操作是对于原\(a\)序列操作,当然也是在\(map\)进行,这也是为什么我们复制一次到\(map\),之后只要出现\(1\)操作,其实之前的所有操作就没有用了,我们只需要记录\(base\)值就行,\(2\)操作正常进行,输出当前的值就是\(mp[i]+base\)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+10;
int a[N];
map<int,int>mp;
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n;
cin>>n;
for(int i = 1;i<=n;i++)
cin>>a[i],mp[i] = a[i];
int q,base = 0;
cin>>q;
while(q--)
{
int op;
cin>>op;
if(op==1)
{
int x;
cin>>x;
base = x;
mp.clear();
}
else if(op==2)
{
int i,x;
cin>>i>>x;
mp[i]+=x;
}
else
{
int i;
cin>>i;
cout<<base+mp[i]<<'\n';
}
}
return 0;
}
E - Grid Filling
Problem Statement
题意:给你一个\(n\)行\(m\)列矩阵,里面有数字,给你一个\(N\),表示里面数字是从\(1\)到\(N\)的。
在给你\(h\)和\(w\)表示你需要把该\(n\)行\(m\)列的大矩阵中的\(h\)行\(w\)列涂黑(相当于暂时不存在),看看操作之后剩余是数字种类。
操作方式如下:
Solution
思路:首先直接暴力肯定是不行的,看见对二维区间操作,我想到了二维前缀和,那是不是可以用前缀和的思想去预处理出一个在二维区间的每个数的个数。
在一开始读入时候统计每个数的个数,之后用二维前缀和思想预处理出每个数的出现情况,之后就是询问部分,每次询问,for一遍1到N,如果\(cnt[i]-sum[i]==0\),那种类数\(-1\)即可,最后输出答案即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 310;
int a[N][N];
int s[N][N][N];
map<int,int>mp;
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n,m,N,h,w;
cin>>n>>m>>N>>h>>w;
for(int i = 1;i<=n;i++)
for(int j = 1;j<=m;j++)
cin>>a[i][j],mp[a[i][j]]++;
for(int x = 1;x<=N;x++)
{
for(int i = 1;i<=n;i++)
{
for(int j = 1;j<=m;j++)
{
s[x][i][j] = s[x][i-1][j]+s[x][i][j-1]-s[x][i-1][j-1];
if(a[i][j]==x)s[x][i][j]++;
}
}
}
// for(int x = 1;x<=N;x++)
// {
// for(int i = 1;i<=n;i++)
// {
// for(int j = 1;j<=m;j++)
// {
// cout<<"x = "<<x<<" i = "<<i<<" j = "<<j<<" ";
// cout<<"s[x][i][j] = "<<s[x][i][j]<<" "<<endl;
// }
// }
// }
for(int i = 1;i<=n-h+1;i++)
{
for(int j = 1;j<=m-w+1;j++)
{
int t = N;
cnt.clear();
int x1 = i,y1 = j,x2 = i+h-1,y2 = j+w-1;
//cout<<"x1 = "<<x1<<" y1 = "<<y1<<" x2 = "<<x2<<" y2 = "<<y2<<endl;
for(int k = 1;k<=N;k++)
{
int sum = s[k][x2][y2]-s[k][x1-1][y2]-s[k][x2][y1-1]+s[k][x1-1][y1-1];
//cout<<"k = "<<k<<" mp[k] = "<<mp[k]<<" sum = "<<sum<<endl;
if(mp[k]-sum==0)t--;
}
cout<<t<<" ";
}
cout<<"\n";
}
return 0;
}