【A~E】AtCoder Beginner Contest 365

A - Leap Year

题目大意

给定 n,求第 n 年的天数(365366)。

思路

显然地,我们需要判断这个是否为闰年。

如果 n 不能被 4 整除,那么不是闰年。

如果 n 可以被 400 整除,那么是闰年。

如果 n 不可以被 100 整除但是可以被 4 整除,那么是闰年。

否则就不是闰年。

很简单。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
	int n;cin>>n;
	
	if(n%4!=0){
		cout<<365;
	}
	else if(n%400==0){
		cout<<366;
	}
	else if((n%100!=0)&&n%4==0){
		cout<<366;
	}
	else cout<<365<<endl;
	
	return 0;
}

B - Second Best

题目大意

给定 {an},求次大值的位置。

思路

打擂。记目前最大值为 max,目前次大值为 cmax

如果 ai>max,那么把 cmax 更新为 max,把 max 更新为 ai,同时记录位置。

如果 ai<max 并且 ai>cmax,那么把 cmax 更新为 ai,同时记录位置。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
	int n;cin>>n;
	vector<int>a(n+1);
	
	for(int i=1;i<=n;i++)
		cin>>a[i];
	
	int ans1=a[1],ans2=0;
	int pos1=1,pos2=0;
		
	for(int i=2;i<=n;i++){
		if(a[i]>ans1){
			ans2=ans1;
			pos2=pos1;
			ans1=a[i];
			pos1=i;
		}
		else if(a[i]>ans2){
			ans2=a[i];
			pos2=i;
		}
	}
	
	cout<<pos2<<endl;
	
	return 0;
}

C - Transportation Expenses

题目大意

给定 {AN},要求 min{Ai,x}M,求最大值 x(可能为无穷大)。

思路

很板的二分答案。

首先考虑无穷大的答案。可以先计算序列的总和和 M 比较,如果这个都小于等于 M,那么肯定答案是无穷大。

如果不是无穷大呢?可以试着枚举一个 x,然后对于每一个 x 判断是否满足题目条件,然后记录最大的 x,时间复杂度 O(NM)

考虑二分一个 x 然后来判断,题目要求 x 的最大值,可以发现若此时的 x 为最大,那么对于每一个 kx 都可以满足题目条件,而对于每一个 kx 都不能满足题目条件,满足单调性,写二分答案,时间复杂度 O(NlogM)

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n,m,a[200005],ans=-1e17;

bool check(int x){
	int res=0;
	for(int i=1;i<=n;i++)
		res+=min(a[i],x);
	return (res<=m);
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		cin>>a[i];
		
	if(check(1e17)){
		cout<<"infinite"<<endl;
		return 0;
	}
	
	int l=0,r=m;
	while(l<=r){
		int mid=(l+r)>>1;
		if(check(mid))ans=mid,l=mid+1;
		else r=mid-1;
	}

    cout<<ans<<endl;
	
	return 0;
}

D - AtCoder Janken 3

题目大意

两个人玩石头剪刀布,已知 A 的出招顺序,而且 B 从来没有输给 A,而且 B 相邻两次的出招是不一样的(比如这次 B 出了石头,那么他下一次就不能出石头),求 B 最多可以赢多少局。

思路

因为发现 B 出招的限制条件只和前一次和后一次的有关,所以这个问题显然满足无后效性,考虑 DP。

fi,0/1 表示已经过了 i 局并且第 iBA 平局或赢(取 0 时两人平局,取 1B 赢)时的最大胜场数。

显然发现通过判断当前局和上一局的平局和胜利的出招是否相同来进行转移。

具体见代码。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;

int n,f[200001][2]={0};
string s;
char lp,lwin;

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
	cin>>n>>s;
	
	f[0][0]=0,f[0][1]=1;
	if(s[0]=='S')lwin='R',lp='S';
	else if(s[0]=='R')lwin='P',lp='R';
	else lwin='S',lp='P';
	
	for(int i=1;i<n;i++){
		char p,win;
		if(s[i]=='S')win='R',p='S';
		else if(s[i]=='R')win='P',p='R';
		else win='S',p='P';
		
		if(p!=lp)f[i][0]=max(f[i-1][0],f[i][0]);
		if(p!=lwin)f[i][0]=max(f[i-1][1],f[i][0]);
		
		if(win!=lp)f[i][1]=max(f[i-1][0]+1,f[i][1]);
		if(win!=lwin)f[i][1]=max(f[i-1][1]+1,f[i][1]);
		
		lp=p,lwin=win;
	}
	
	cout<<max(f[n-1][0],f[n-1][1])<<endl;
	
	return 0;
}

E - Xor Sigma Problem

题目大意

给定 {AN},求 i=1N1j=i+1NAiAi+1Aj

思路

考虑一下这道题的弱化版:求序列中两两异或的总和,也就是求 i=1N1j=i+1NAiAj

不难发现,正常求是需要 O(N2) 的复杂度,考虑拆位。

也就是把每一个数都拆成二进制位,比如对于 A={2,3,5,8},那么拆位之后就是:

2:0 0 1 0

3:0 0 1 1

5:0 1 0 1

8:1 0 0 0

可以发现,每一位的贡献其实都是这一位上两两异或为 1 的贡献。

也就是说,第一位会产生 3 的贡献(3011)。

以此类推,每一位的贡献分别为 3344

那么乘上每一位的权重,可以得出答案为:

3×23+3×22+4×21+4×20=48

再来考虑一下原问题,不难发现我们可以预处理出一个异或前缀 s,也就是 si=si1Ai,那么类似前缀和,根据异或的自反性质,区间 [l,r] 的异或为 srsl1

也就是说,我们目前得到了所有的区间的异或值,不难看出原题的答案就是:

i=1Nsi+i=2Nsis1++i=N1NsisN2i=1NAi

这个式子看起来挺复杂吧?

其实再深入思考一下就可以发现其实中间的那一大串(i=2Nsis1++i=N1NsisN2)拆开来看,其实就是 s1sN 的两两异或!

也就是说,我们可以根据 si 来重新建一个序列,求完了这个序列的两两异或和之后再加上 si,然后因为原题中没有包含 Ai 的情况,所以还要再减去 Ai

具体见代码。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;

int ans[20]={0};
int b[200001];
int sum[200001]={0};
long long res=0;
int n,a,i,len,mx=-1;

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
    cin>>n;
    for(int i=1;i<=n;i++)cin>>b[i];
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]^b[i];
    
    for(i=1;i<=n;i++){
        a=sum[i];
        len=0;
        while(a){
            len++;
            if(a&1)ans[len]++;
            a=a>>1;
        }
        mx=max(mx,len);
    }
    
    for(i=1;i<=mx;i++)
        res+=(1ll<<(i-1))*ans[i]*(n-ans[i]);
    
    for(int i=1;i<=n;i++)
    	res+=sum[i],res-=b[i];
    
    cout<<res;
    
    return 0;
}
posted @   SnapYust  阅读(272)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示