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(); 
	}

}
posted @ 2025-12-08 19:17  LYET  阅读(33)  评论(0)    收藏  举报