Atcoder Beginner Contest 410 A-F题解
AB
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
int n,k;
int a[maxn];
int main(){
int in;
int ans=0;
read(n);
for(int i=1;i<=n;i++){
read(a[i]);
}
read(k);
for(int i=1;i<=n;i++){
if(k<=a[i]) ++ans;
}
printf("%d",ans);
return 0;
}
B题注意数据范围,100的话直接暴力就可以了
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
int a[maxn];
int n,q;
int main(){
read(n),read(q);
int in;
for(int i=1;i<=q;i++){
read(in);
if(in==0){
int ansi=n;
for(int i=n-1;i>=1;i--){
if(a[ansi]>=a[i]) ansi=i;
}
++a[ansi];
printf("%d ",ansi);
}
else{
++a[in];
printf("%d ",in);
}
}
return 0;
}
C
唯一会改变序列的操作只有重复 将A的第一个元素移至末尾 的操作k次
所有只要维护一个序列开头就好了
注意k的数据范围较大,记得及时取余,嫌麻烦开long long也可以
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
int a[maxn];
int n,q;
int p=0;
int main(){
read(n),read(q);
for(int i=1;i<=n;i++) a[i]=i;
int op,x;
for(int i=1;i<=q;i++){
read(op),read(x);
if(op==3){
p=(p-1+x)%n+1;
}
else if(op==2){
x=(p+x-1)%n+1;
printf("%d\n",a[x]);
}
else{
int k;
read(k);
x=(p+x-1)%n+1;
a[x]=k;
}
}
return 0;
}
D
数据范围较小,搜索就可以了
状态也很少,开个布尔类型的二维数组记录就好了,即i点能不能到达j的值
我也在想能不能用位运算特点做,但暂时没想到
这道题卡dfs,请用bfs解决
#include<bits/stdc++.h>
using namespace std;
const int maxn=1025;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
struct edge{
int v;
long long w;
};
struct bs{
int u;
long long w;
};
int head[maxn],nxt[maxn];
edge e[maxn];
int cnt;
void init_mp(){
memset(head,-1,sizeof(head));
cnt=-1;
return;
}
void add_edge(int u,int v,int w){
e[++cnt]=(edge){v,w};
nxt[cnt]=head[u];
head[u]=cnt;
return;
}
int n,m;
int vis[maxn];
int f[maxn][maxn];
void bfs(){
queue<edge> q;
q.push((edge){1,0});
while(!q.empty()){
edge u=q.front();
q.pop();
for(int i=head[u.v];~i;i=nxt[i]){
if(!f[e[i].v][e[i].w^u.w]){
f[e[i].v][e[i].w^u.w]=1;
q.push((edge){e[i].v,e[i].w^u.w});
}
}
}
return;
}
int main(){
read(n),read(m);
int u,v,w;
init_mp();
for(int i=1;i<=m;i++){
read(u),read(v),read(w);
add_edge(u,v,w);
}
bfs();
for(int i=0;i<maxn;i++){
if(f[n][i]){
printf("%d",i);
return 0;
}
}
printf("-1");
return 0;
}
E
动态规划,类似于背包问题,设计状态f[i]如下:
当生命值为i时,能够保留的最多魔力值
初始化每个f[i]为m
状态转移方程如下:
if(i<a) f[i]-=b; 若生命不够,使用魔力
else f[i]=max(f[i]-b,f[i-a]); 若生命足够,选择最优解
每次只要看所有f[i]中还有没有大于或等于0的就可以判断该怪兽能不能被打败
注意点:生命和魔力值可以为0,怪兽是按照顺序打的
#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
int f[maxn];
int n,h,m;
int main(){
read(n),read(h),read(m);
for(int i=0;i<=h;i++) f[i]=m;
int a,b;
int ans=-1;
for(int i=1;i<=n;i++){
read(a),read(b);
if(ans>-1) continue;
bool ed=0;
for(int i=h;i>=0;i--){
if(i<a) f[i]-=b;
else f[i]=max(f[i]-b,f[i-a]);
if(f[i]>=0) ed=1;
}
if(!ed) ans=i-1;
}
printf("%d",ans==-1 ? n : ans);
return 0;
}
F
第一道补出来的F题
涉及矩阵的题,可以联想到计算每一列的前缀和,然后枚举两个行坐标,在行内进行双指针操作,详见洛谷P8783
不过这道题显然不能用双指针,但是前一步的优化操作可以采取
先把矩阵转换为-1,1的矩阵,然后问题就变成了矩阵和为0
通过这样的方法在几行之间求前缀和,可以得出如果某两个位置的前缀和相同,那么该矩阵和为0
这里还有两点优化:
1.时间复杂度为O(n*n*m),n取n,m中较小的
2.使用map会超时,这里用的是数组+偏移来用作桶,同时用队列记录发生改变的量以便归零
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
void read(char& c){
do{
c=getchar();
}while(c==10||c==13);
return;
}
int q;
int n,m;
vector<vector<int> > mp;
int t[maxn<<1];
int main(){
read(q);
char in;
while(q--){
read(n),read(m);
if(n>m){
mp.resize(m+1);
for(int i=0;i<=m;i++) mp[i].resize(n+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
read(in);
if(in=='.') mp[j][i]=-1;
else mp[j][i]=1;
}
}
swap(n,m);
}
else{
mp.resize(n+1);
for(int i=0;i<=n;i++) mp[i].resize(m+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
read(in);
if(in=='.') mp[i][j]=-1;
else mp[i][j]=1;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
mp[i][j]+=mp[i-1][j];
}
}
long long ans=0;
queue<int> que;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
int p=0;
t[maxn]=1;
for(int k=1;k<=m;k++){
p+=mp[j][k]-mp[i-1][k];
ans+=t[p+maxn];
if(!t[p+maxn]) que.push(p+maxn);
++t[p+maxn];
}
while(!que.empty()){
t[que.front()]=0;
que.pop();
}
}
}
printf("%lld\n",ans);
}
return 0;
}

浙公网安备 33010602011771号