ABC 365
赛时通过:A、B、C。
赛后补题:D、E。
A
依题判断即可。
#include<bits/stdc++.h>
using namespace std;
int y;
int main(){
cin>>y;
if(y%4!=0) cout<<365;
if(y%4==0&&y%100!=0) cout<<366;
if(y%100==0&&y%400!=0) cout<<365;
if(y%400==0) cout<<366;
}
B
排序即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e2+5;
int n;
pair<int,int> a[N];
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].first,a[i].second=i;
sort(a+1,a+n+1);
cout<<a[n-1].second;
return 0;
}
C
显然 \(x\) 越大,总费用越大,具有单调性。二分即可求出最大的 \(x\)。
当 $ \sum a_i > M$ 时,\(x\) 便可无限大。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n,m,a[N];
bool check(int x){
int s=0;
for(int i=1;i<=n;i++) s+=min(x,a[i]);
return s<=m;
}
signed main(){
ios::sync_with_stdio(0);
cin>>n>>m;
int s=0;
for(int i=1;i<=n;i++) cin>>a[i],s+=a[i];
if(s<=m) cout<<"infinite",exit(0);
int l=0,r=m+1;
while(l+1<r){
int mid=(l+r)>>1;
if(check(mid)) l=mid;
else r=mid;
}
cout<<l;
return 0;
}
D
首先贪心是错误的。详情见这份 Hack https://atcoder.jp/contests/abc365/editorial/10601 (https://atcoder.jp/contests/abc365/editorial/10601)。
然后考虑 dp。因为过于简单,所以具体细节见代码。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int n;
string s;
int dp[N][3];
//0/1/2:R/P/S
//R->S S->P P->R
signed main(){
ios::sync_with_stdio(0);
cin>>n>>s,s="#"+s;
if(s[1]=='R')
dp[1][0]=0,
dp[1][1]=1,
dp[1][2]=-1e9;
else if(s[1]=='P')
dp[1][0]=-1e9,
dp[1][1]=0,
dp[1][2]=1;
else
dp[1][0]=1,
dp[1][1]=-1e9,
dp[1][2]=0;
for(int i=2;i<=n;i++){
if(s[i]=='R')
dp[i][0]=max(dp[i-1][1],dp[i-1][2]),
dp[i][1]=max(dp[i-1][0],dp[i-1][2])+1;
else if(s[i]=='P')
dp[i][1]=max(dp[i-1][0],dp[i-1][2]),
dp[i][2]=max(dp[i-1][0],dp[i-1][1])+1;
else
dp[i][0]=max(dp[i-1][1],dp[i-1][2])+1,
dp[i][2]=max(dp[i-1][0],dp[i-1][1]);
}
cout<<max({dp[n][0],dp[n][1],dp[n][2]});
}
E
灵茶八题 T3。
看到异或运算,考虑二进制拆位。
考虑异或的一个性质:
\[S_r \oplus S_{l-1} = \oplus ^ {r} _ {i=l} A_i
\]
其中:
\[S_i=\oplus ^ {i} _ {j=1} A_j
\]
(这是因为,\(S_r\) 与 \(S_{l-1}\) 的相同部分会被消去)
于是,我们求出 \(S\) 数组(\(n+1\) 位),其中第 \(0\) 位是为了提取长度为 \(1\) 的子数组。
能提取出一个子数组,当且仅当 \(S_r\) 与 \(S_{l-1}\) 的某一位的异或值为 \(1\),不然这俩的贡献就是 \(0\)。
考虑二进制拆位。对于 \(S\) 数组中的每一位,只有两位分别是 \(0,1\) 时,才会有贡献。
于是我们统计出每一位中 \(1\) 的个数 \(x\),则 \(0\) 的个数即为 \(n+1-x\),通过乘法原理计算可得贡献即为 \((n+1-x) \times x\),再乘上 \(2^j\) 即为当前位的贡献,累加即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,M=31;
int n,ans;
int a[N],s[N];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i],s[i]=s[i-1]^a[i];
}
int ans=0;
for(int j=0;j<31;j++){
int cnt=0;
for(int i=0;i<=n;i++) cnt+=s[i]>>j&1;
ans+=(cnt)*(n+1-cnt)*(1<<j);
}
for(int i=1;i<=n;i++) ans-=a[i];
cout<<ans;
return 0;
}