Codeforces Round 1068 (Div. 2) A-D
A. Sleeping Through Classes
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,k;
cin>>n>>k;
string s;
cin>>s;
int ans=0,now=0;
for(auto ch:s){
if(ch=='1'){
now=k;
}
else{
if(now) now--;
else ans++;
}
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
B. Niko's Tactical Cards
简单 DP
\(f[i] [0/1]\) 表示前 \(i\) 卡片的最大/最小值
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1),b(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
vector<vector<int>> f(n+1,vector<int>(2));
for(int i=1;i<=n;i++){
f[i][0]=max(f[i-1][0]-a[i],b[i]-f[i-1][1]);
f[i][1]=min(f[i-1][1]-a[i],b[i]-f[i-1][0]);
// cout<<f[i][0]<<" "<<f[i][1]<<endl;
}
cout<<f[n][0]<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
C. Kanade's Perfect Multiples
首先,\(b\) 中的值一定是 \(a\) 中出现过的
可以从大到小枚举 \(a\) 中的元素 \(val\),如果 \(val\) 没有被标记过,就将 \(val\) 放入 \(b\) 中,再检查所有小于等于 \(k\) 的 \(val\) 的倍数是否出现,如果出现,将这个倍数标记,否则不符合题意,输出 \(-1\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n,k;
cin>>n>>k;
set<int> st;
for(int i=1;i<=n;i++){
int val;
cin>>val;
st.insert(val);
}
set<int> ans;
map<int,int> mp;
for(auto val:st){
if(mp[val]) continue;
for(int i=val;i<=k;i+=val){
if(st.count(i)){
mp[i]=1;
}
else{
cout<<-1<<endl;
return;
}
}
ans.insert(val);
}
cout<<ans.size()<<endl;
for(auto val:ans){
cout<<val<<" ";
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}
D. Taiga's Carry Chains
对于 \(a+b\),过程中产生的进位次数 = \(popcount(a)+popcount(b)-popcount(a+b)\)
设最后的结果是 \(ans\),则进位次数为:\(popcount(n)+k-popcount(ans)\)
所以要最小化最后结果二进制位中 \(1\) 的数量
\(n\) 最多有 \(30\) 位,所以如果 \(k>=30\),就一定能将 \(n\) 变成一个 \(2\) 的幂,此时最后结果二进制位中 \(1\) 的数量就是 \(1\) ,此时答案为 \(popcount(n)+k-1\)
当 \(k<30\) 时,如何最小化二进制位中 \(1\) 的数量?
设 \(dp[i] [j] [x]\),表示:当前计算到第 \(i\) 位,已经使用 \(j\) 次操作,且当前状态给 \(i+1\) 位的进位是 \(x~(x=0/1)\) ,的前 \(i\) 位 \(popcount\) 最小值
可以使用记忆化搜索实现
转移时,当前位的值为 \(now\), 可以枚举当前位置的操作 \(op=0/1\) 和上一个状态给的进位 \(carry=0/1\)
如果 \((now+op+carry)/2!=x\),则表示位置当前位给下一位的进位,不等于当前状态的进位值 \(x\),所以这个转移是非法的
搜索的终点是 \(i=-1\),需要特判 \(i=-1\) 时不可以有进位
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
int popcount(int x){
return __builtin_popcountll(x);
}
void solve(){
int n,k;
cin>>n>>k;
if(k>=30){
cout<<popcount(n)+k-1<<endl;
return;
}
// f[i][j][k]
//表示:处理到第 i 位,已经用了 j 次,且给更高位的进位是 k 的 popcount 最小值
int f[35][35][2];
memset(f,-1,sizeof f);
f[0][0][0]=n&1;
auto dp=[&](auto dp,int i,int j,int x)->int {
if(i<0){
//特判,第-1位给第0位的进位只能是0
return (x==0)?0:inf;
}
if(f[i][j][x]!=-1) return f[i][j][x];
int now=(n>>i)&1;
int res=inf;
for(int op=0;op<=1;op++){
for(int carry=0;carry<=1;carry++){
if((now+op+carry)/2!=x) continue;
if(j-op>=0) res=min(res,dp(dp,i-1,j-op,carry)+((now+op+carry)&1));
}
}
return f[i][j][x]=res;
};
cout<<popcount(n)+k-dp(dp,32,k,0)<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t=1;
cin>>t;
while(t--){
solve();
}
}

浙公网安备 33010602011771号