cf 板刷日记(1700-1900)二

D. Find the Last Number

Codeforces Round 1061 (Div. 2)

https://codeforces.com/problemset/problem/2156/D

交互题,每次查询所有数某一位的值,看看这一位 0/1 出现的数量哪一个和实际数量不符,则答案的这一位就是几

每次可以排除一半,所以查询差不多就是 \(2*n\)

点击查看代码
#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 query(int i,int x){
    cout<<"? "<<i<<" "<<x<<endl;
    int res;
    cin>>res;
    return res;
}

void solve(){
    int n;
    cin>>n;

    vector<int> t,ans;
    for(int i=1;i<n;i++){
        t.push_back(i);
        ans.push_back(i);
    }
    ans.push_back(n);

    int j=0;
    while(t.size()){
        vector<vector<int>> mp(60,vector<int>(2));

        for(auto i:ans){
            int j=0,val=i;
            for(int k=0; k<20; k++){
                int now = (i >> k) & 1;
                mp[k][now]++;
            }
        }
        vector<int> o,l,tmp;
        int c0=0,c1=0;
        for(auto idx:t){
            int res=query(idx,(1<<j));
            if(res==0){
                o.push_back(idx);
                c0++;
            }
            else{
                l.push_back(idx);
                c1++;
            }
        }
        if(c0<mp[j][0]){    
            t=o;
            for(auto val:ans){
                if(((val>>j)&1)==0) tmp.push_back(val);
            }
            ans=tmp;
        }
        else{
            t=l;
            for(auto val:ans){
                if(((val>>j)&1)) tmp.push_back(val);
            }
            ans=tmp;
        }

        j++;
    }

    cout<<"! "<<ans.back()<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

D. Batteries

Codeforces Round 1056 (Div. 2)

https://codeforces.com/problemset/problem/2155/D

妙妙题

限制条件是 \(n*n/a\) 次查询,考虑如何利用 \(a\) 这个信息

假设将 \(n\) 个点连成一个环,则两个能用的电池之间的距离不超过 \(n/a\)

所以对每个点,可以暴力判断后面的 \(n/a\) 个点。一定能找到答案,

点击查看代码
#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,a;
    cin>>n;

    for(int a=1;a<=n;a++){
        for(int i=1;i<=n;i++){
            if(i+a>n) cout<<i<<" "<<i+a-n<<endl;
            else cout<<i<<" "<<i+a<<endl;
            int res;
            cin>>res;
            if(res) return;
        }
    }
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

D. Catshock

Codeforces Round 1060 (Div. 2)

https://codeforces.com/problemset/problem/2154/D

真有 1900 吗能让我这么容易的切出来

\(1-n\) 简单路径上的点为主线,其他点为直线

大致思路是,先把支线的点按照深度从深到浅删完,再把主线的点从 \(1\)\(n\) 删完

删支线点时,将所有支线点按照深度从大到小排序,每次删最深的那个点。

如果当前猫猫所在点的寄偶性和要删的点相同,就让猫猫移动一次,否则让猫猫移动两次。

(从大到小删是为了保证删掉这个点后,猫猫一定和主线联通)

处理主线的方式同理

好简单的 1900,分析一下奇偶性就没了

点击查看代码
#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<vector<int>> g(n+1);
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    vector<int> fa(n+1),dep(n+1),st(n+1);
    
    auto dfs=[&](auto dfs,int u,int pre)->void {
        fa[u]=pre;
        dep[u]=dep[pre]+1;
        for(auto v:g[u]){
            if(v==pre) continue; 
            dfs(dfs,v,u);
        }
    };

    dfs(dfs,1,0);

    vector<pii> t;
    vector<pii> ans;
    
    int now=n;
    while(fa[now]){
        st[now]=1;
        now=fa[now];
    }

    for(int i=1;i<=n;i++){
        if(!st[i]){
            t.push_back({dep[i],i});
        }
    }

    now=1;
    sort(t.begin(),t.end());

    //删掉所有支线
    while(t.size()){
        auto [dp,u]=t.back();

         if(now==(dp&1)){
            ans.push_back({1,0});
            now^=1;
         }
         else{
            ans.push_back({1,0});
            ans.push_back({1,0});
         }
         ans.push_back({2,u});
         t.pop_back();
    }

    for(int i=1;i<=n;i++){
        if(st[i]){
            t.push_back({dep[i],i});
        }
    }

    sort(t.begin(),t.end(),greater<pii>());

    while(t.size()>1){
        auto [dp,u]=t.back();

         if(now==(dp&1)){
            ans.push_back({1,0});
            now^=1;
         }
         else{
            ans.push_back({1,0});
            ans.push_back({1,0});
         }
         ans.push_back({2,u});
         t.pop_back();
    }

    cout<<ans.size()<<endl;
    for(auto [a,b]:ans){
        if(b) cout<<a<<" "<<b<<endl;
        else cout<<a<<endl;
    }
    cout<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

D. Division Versus Addition

Squarepoint Challenge (Codeforces Round 1055, Div. 1 + Div. 2)

https://codeforces.com/problemset/problem/2152/D

对于所有的数,计算出每次先 +1 再 /2 和先 /2 再 +1,两种情况的操作次数

如果某个数两种方式的操作次数一样,则不重要,否则重要

对于两个人的操作,显然是要抢所有重要的数,的第一次操作

设有 \(k\) 个重要的数,则第一个人可以抢得到 \((k+1)/2\) 个数的第一次

点击查看代码
#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,q;
    cin>>n>>q;
    vector<int> a(n+1),b(n+1),c(n+1),d(n+1);

    for(int i=1;i<=n;i++){
        cin>>a[i];

        int val=a[i];
        while(val>1){
            val++;
            val>>=1;
            b[i]++;
        }

        val=a[i];
        while(val>1){
            val>>=1;
            if(val>1) val++;
            c[i]++;
        }
        d[i]=b[i]-c[i];
        d[i]+=d[i-1];
        b[i]+=b[i-1];
    }

    while(q--){
        int l,r;
        cin>>l>>r;

        cout<<b[r]-b[l-1]-(d[r]-d[l-1]+1)/2<<endl;
    }


}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

D. Not Alone

Codeforces Round 1057 (Div. 2)

https://codeforces.com/problemset/problem/2153/D

相当于把整个序列分成很多段,令每段的元素都相等的最小代价

最优分段方式的段长显然只有 \(2\)\(3\) 就行了,简单 DP 即可

处理环时,可以分别在原数组上处理一次,把 \(a[1]\) 放到最后处理一次,把 \(a[1],a[2]\) 放到最后处理一次

点击查看代码
#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);

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    auto wk=[&](int idx)-> int {
        vector<int> t;
        t.push_back(0);
        for(int i=idx;i<=n;i++){
            t.push_back(a[i]);
        }
        for(int i=1;i<idx;i++){
            t.push_back(a[i]);
        }

        vector<int> f(n+1,inf);

        f[2]=abs(t[1]-t[2]);
        f[3]=max({t[1],t[2],t[3]})-min({t[1],t[2],t[3]});

        for(int i=4;i<=n;i++){
            f[i]=min(f[i-2]+abs(t[i-1]-t[i]),f[i-3]+max({t[i],t[i-1],t[i-2]})-min({t[i],t[i-1],t[i-2]}));
        }

        return f[n];
    };

    int ans=inf;
    for(int i=1;i<=3;i++){
        ans=min(ans,wk(i));
    }

    cout<<ans<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

B. Grid Counting

Codeforces Round 1053 (Div. 1)

https://codeforces.com/problemset/problem/2150/B

为了满足条件二,三,每列必须填一个,而且左右第 \(i\) 列必须在前 \(i\) 行填完

推出,前 \(\lceil n/2 \rceil\) 行必须把 \(n\) 列都填完。

从上往下对每行统计方案数很困难,从下往上组合数学统计方案数即可

点击查看代码
#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;

/*支持define int long long 的自动取模类*/
template<const int T>
struct ModInt {
    const static int mod = T;
    int x;
    ModInt(signed x = 0) : x(x % mod) {}
    ModInt(long long x) : x((int)x % mod) {} 
    int val() { return x; }
    ModInt operator + (const ModInt &a) const { int x0 = x + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
    ModInt operator - (const ModInt &a) const { int x0 = x - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
    ModInt operator * (const ModInt &a) const { return ModInt(1LL * x * a.x % mod); }
    ModInt operator / (const ModInt &a) const { return *this * a.inv(); }
    bool operator == (const ModInt &a) const { return x == a.x; };
    bool operator != (const ModInt &a) const { return x != a.x; };
    void operator += (const ModInt &a) { x += a.x; if (x >= mod) x -= mod; }
    void operator -= (const ModInt &a) { x -= a.x; if (x < 0) x += mod; }
    void operator *= (const ModInt &a) { x = 1LL * x * a.x % mod; }
    void operator /= (const ModInt &a) { *this = *this / a; }
    friend ModInt operator + (int y, const ModInt &a){ int x0 = y + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
    friend ModInt operator - (int y, const ModInt &a){ int x0 = y - a.x; return ModInt(x0 < 0 ? x0 + mod : x0); }
    friend ModInt operator * (int y, const ModInt &a){ return ModInt(1LL * y * a.x % mod);}
    friend ModInt operator / (int y, const ModInt &a){ return ModInt(y) / a;}
    friend ostream &operator<<(ostream &os, const ModInt &a) { return os << a.x;}
    friend istream &operator>>(istream &is, ModInt &t){return is >> t.x;}

    ModInt pow(int64_t n) const {
        ModInt res(1), mul(x);
        while(n){
            if (n & 1) res *= mul;
            mul *= mul;
            n >>= 1;
        }
        return res;
    }
    
    ModInt inv() const {
        int a = x, b = mod, u = 1, v = 0;
        while (b) {
            int t = a / b;
            a -= t * b; swap(a, b);
            u -= t * v; swap(u, v);
        }
        if (u < 0) u += mod;
        return u;
    }
    
};
using mint = ModInt<mod>;

const int N=2e5+1;
vector<int> fact(N),infact(N);

int qmi(int a,int b,int p){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1; 
    }
    return res;
}

void init(){
    fact[1]=1;
    fact[0]=1;
    infact[0]=1;
    infact[1]=1;

    for(int i=2;i<N;i++){
        fact[i]=fact[i-1]*i%mod;
        infact[i]=qmi(fact[i],mod-2,mod);
    }
}

int C(int a,int b){
    if(a<b) return 0;

    return fact[a]*infact[b]%mod*infact[a-b]%mod;
}

void solve(){
    int n;
    cin>>n;

    vector<int> a(n+1);
    vector<int> nd(n+1);

    for(int i=1;i<=n;i++){
        cin>>a[i];
    }

    for(int i=1;i<=n/2;i++){
        nd[i]=2;
    }
    if(n&1) nd[(n+1)/2]=1;

    int now=0;
    mint ans=1;
    for(int i=n;i>=1;i--){
        now+=nd[i];
        if(a[i]>now) {
            cout<<0<<endl;
            return;
        }
        ans*=C(now,a[i]);
        now-=a[i];
    }
    if(now!=0){
        cout<<0<<endl;
        return;
    }
    cout<<ans<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    init();

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

D. Game on Array

Codeforces Global Round 29 (Div. 1 + Div. 2)

https://codeforces.com/problemset/problem/2147/D

初始时,数值为偶数的值,在双方都使用最优策略时没有影响,所以只考虑初始时值为奇数的数字。

对值为奇数的每个数字各取一次变成偶数,而偶数就是双方均分

所以双方各取一半奇数的第一次即可

点击查看代码
#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;

    map<int,int> mp;

    for(int i=1;i<=n;i++){
        int val;
        cin>>val;
        mp[val]++;
    }

    int a=0,b=0;
    vector<int> t;
    
    for(auto [val,cnt]:mp){
        a+=cnt*(val/2);
        b+=cnt*(val/2);
        if(val&1){
            t.push_back(cnt);
        }
    }

    sort(t.begin(),t.end(),greater<int>());

    for(int i=0;i<t.size();i++){
        if(i&1) b+=t[i];
        else a+=t[i];
    }

    cout<<a<<" "<<b<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

F. Gravity Falls

Codeforces Round 1050 (Div. 4)

https://codeforces.com/problemset/problem/2148/F

模拟过程即可,假设当前 \(k\) 位已被确定,则可以在此时对所有字符串排序,排序依据是所有字符串 \(k+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;
    cin>>n;
    vector<vector<int>> a(n+1);
    int mxk=0;

    for(int i=1;i<=n;i++){
        int k;
        cin>>k;
        mxk=max(k,mxk);
        vector<int> t(k+1);
        for(int j=1;j<=k;j++){
            cin>>t[j];
        }
        a[i]=t;
    }

    vector<vector<int>> ans(1);
    vector<int> st(n+1);

    int idx=1;

    auto check=[&](int t1,int t2,int val)-> bool {
       auto s1=a[t1];
       auto s2=a[t2];
        for(int i=val;i<=mxk;i++){
            if(s1.size()<=i) return 1;
            if(s2.size()<=i) return 0;
            if(s1[i]<s2[i]) return 1;
            if(s1[i]>s2[i]) return 0;
        }
        return 1;
    };

    while(idx<=mxk){
        int now=0;
        for(int i=1;i<=n;i++){
            if(st[i]) continue;
            if(a[i].size()-1<idx) continue;
            if(now==0) now=i;
            else{
                if(check(i,now,idx)){
                    now=i;
                }
            }
        }
        ans.push_back(a[now]);
        idx=a[now].size();
    }

   for(int i=1;i<=mxk;i++){
        for(int j=1;j<ans.size();j++){
            if(ans[j].size()>i){
                cout<<ans[j][i]<<' ';
                break;
            }
        }
   }
   cout<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    cin>>ct;

    while(ct--){
        solve();
    }
}

G. Farmer John's Last Wish

Codeforces Round 1050 (Div. 4)

https://codeforces.com/problemset/problem/2148/G

好妙的题,看明白题解的时候神清气爽

对于新加进来的一个数,两种情况

  1. 放到最后一个,则前面 \(gcd\) 的所有因数一定有有一个是当前数不存在的。这里直接用 \(gcd\) 算一下就行

  2. 放到前面,不让当前数作为第 \(k+1\) 个数,则此时可以枚举当前数的所有因数,对于一个因数 \(t\),看看当前序列中有多少个数

  3. 继承前一个数的答案 \(ans[i]=ans[i-1]\)

  4. 放到前面,且让当前数作为第 \(k+1\) 个数,但这种情况已经被 \(ans[i-1]\) 覆盖

1187E E. Tree Painting

换根DP。

点击查看代码
#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<vector<int>> g(n+1);

    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    vector<int> sz(n+1);

    auto dfs=[&](auto dfs,int u,int pre)-> void {
        sz[u]=1;
        for(auto v:g[u]){
            if(v==pre) continue;
            dfs(dfs,v,u);
            sz[u]+=sz[v];
        }
    };

    dfs(dfs,1,0);

    vector<int> ans(n+1);
    
    auto f=[&](auto f,int u,int pre)-> void {

        for(auto v:g[u]){
            if(v==pre) continue;
            ans[v]=ans[u]-sz[v]+(n-sz[v]);
            int pu=sz[u],pv=sz[u];
            sz[u]=n-sz[v];
            sz[v]=n;
            f(f,v,u);
            sz[v]=pv,sz[u]=pu;
        }
    };

    for(int i=1;i<=n;i++){
        ans[1]+=sz[i];
    }

    f(f,1,0);

    int t=0;
    for(int i=1;i<=n;i++){
        t=max(t,ans[i]);
    }

    cout<<t<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int ct=1;
    // cin>>ct;

    while(ct--){
        solve();
    }
}
posted @ 2026-02-01 09:48  LYET  阅读(26)  评论(0)    收藏  举报