Atcoder Beginner Contest 407题解A-E
赛时切了4道,E题赛后20分钟就切出来了
AB
#include<bits/stdc++.h>
using namespace std;
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 maxi(int x,int y){
return x<y ? y : x;
}
int mini(int x,int y){
return x>y ? y : x;
}
int main(){
int a,b;
read(a),read(b);
double p=a*1.0/b;
double m=ceil(p),n=floor(p);
if(m-p>p-n) printf("%.0lf",n);
else printf("%.0lf",m);
return 0;
}
其实直接round(p)就可以了,不过赛时没想到
#include<bits/stdc++.h>
using namespace std;
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 maxi(int x,int y){
return x<y ? y : x;
}
int mini(int x,int y){
return x>y ? y : x;
}
int x,y;
int main(){
read(x),read(y);
int ans=0;
for(int i=1;i<=6;i++){
for(int j=1;j<=6;j++){
if(i+j>=x||abs(i-j)>=y){
++ans;
}
}
}
printf("%.18Lf",(long double)ans/36);
return 0;
}
数据范围太小,没必要使用数学方法,暴力枚举即可
C
可以从后向前想:
因为第n位一定是前一个状态加上一个0后,在整体位移a[n]后得到的
所以就能知道在到达n位之前,n-1应该长什么样
(sum表示第i位到第n位的和,ans表示该位所需要的位移次数)
sum+ans≡a[i](mod 10)
ans≡a[i]-sum(mod 10)
由此可知做出第i位所需要的操作次数为(a[i]+10-sum)%10
#include<bits/stdc++.h>
using namespace std;
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 maxi(int x,int y){
return x<y ? y : x;
}
int mini(int x,int y){
return x>y ? y : x;
}
string s;
int main(){
cin>>s;
long long ans=0;
int sum=0;
for(int i=s.size()-1;i>=0;i--){
int k=s[i]-48;
ans+=(k+10-sum)%10;
sum=ans%10;//sum及时取余,否则k+10-sum有可能变为负数
}
printf("%lld",ans+s.size());
return 0;
}
D
算法题思维含量就不大了,看到HW<=20 直接暴力dfs即可。
再应用一下位异或的性质,a^a=0 0^a=a
只要算出异或总和,去掉某个值时再异或它一次就可以了
#include<bits/stdc++.h>
using namespace std;
const int maxn=25;
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(long long& 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;
}
long long maxi(long long x,long long y){
return x<y ? y : x;
}
int n,m;
long long ans=0;
long long a[maxn][maxn];
bool vis[maxn][maxn];
int wx[4]={0,0,-1,1},wy[4]={-1,1,0,0};
void dfs(int x,int y,long long sum){
ans=maxi(ans,sum);
if(y>m) y=1,++x;
if(x>n) return;
if(vis[x][y]){
dfs(x,y+1,sum);
return;
}
for(int i=0;i<4;i++){
int xi=x+wx[i],yi=y+wy[i];
if(xi>=1&&xi<=n&&yi>=1&&yi<=m&&(!vis[xi][yi])){
vis[xi][yi]=vis[x][y]=1;
dfs(x,y+1,sum^a[x][y]^a[xi][yi]);
vis[xi][yi]=vis[x][y]=0;
}
}
dfs(x,y+1,sum);
return;
}
int main(){
read(n),read(m);
long long sum=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
read(a[i][j]);
sum^=a[i][j];
}
}
dfs(1,1,sum);
printf("%lld",ans);
return 0;
}
E
贪心思想,先全拿最大值。
因为括号匹配要求是从后往前k项中右括号数量一定大于左括号数量。
所以从后往前计算,遇到左括号数量大于右括号数了就从中去掉权值最小的那个。
然后在1到i-1中找到最大的还未添加过的,添加上去即可
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+1;
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(long long& 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 num{
int id;
long long p;
};
bool cmp(num a,num b){
return a.p>b.p;
}
bool vis[maxn<<1];
num p[maxn<<1];
long long a[maxn<<1];
int n,t;
int main(){
read(t);
while(t--){
read(n);
for(int i=1;i<=2*n;i++){
read(p[i].p);
a[i]=p[i].p;
p[i].id=i;
}
sort(p+1,p+2*n+1,cmp);
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) vis[p[i].id]=1;
int cnt=n+1;//候选最大添加值
int sum=0;
long long ans=0;
priority_queue<int,vector<int>,greater<int> > k; //保存当前所有权值中最小的
for(int i=2*n;i>=1;i--){
sum+=vis[i];
ans+=vis[i]*a[i];
if(vis[i]) k.push(a[i]);
if((2*n-i+1)-sum<sum&&i>1){//判断左括号数量大于右括号数
ans-=k.top();
k.pop();
--sum;
while(p[cnt].id>=i){
++cnt;
}
vis[p[cnt].id]=1;
//这里不需要再添加了,vis设为true后会在后续的遍历中添加上去的
++cnt;
}
}
printf("%lld\n",ans);
}
return 0;
}
FG
待补

浙公网安备 33010602011771号