Baozii Summer Training Camp Round 2 (C, F, A)

C. Yet Another Array Problem

题意:大小为 \(n\) 的数组 \(a\),找到对于每一个 \(0<=r<k\),有多少个 \(a\) 的子集满足子集和 \(mod~~k~=r\)

纯背包问题,定义 \(f[i][j]\) 表示从前 \(i\) 个数中选,子集和为 \(j\) 的子集数量

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long; 
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 998244353;

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

    vector<int> a(n+1);
    vector<mint> f(k+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i]%=k;
    }

    //f[i][j]=f[i-1][j]+f[i-1][(j-a[i]+k)%k];

    f[0]=1;
    for(int i=1;i<=n;i++){
        vector<mint> nf(k+1);
        for(int j=0;j<k;j++){
            nf[j]=f[j]+f[(j-a[i]+k)%k];

        }
        f=nf;
    }

    for(int j=0;j<k;j++){
        cout<<f[j]<<" ";
    }
    
}

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

    int ct=1;
    // cin>>ct;
    while(ct--) solve();

    return 0;
}

自动取模类:

点击查看代码
/*支持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>;

F. Yet Another Digit DP Problem

题意:如果一个数的数位递增则这个数是 tobo 数,例如 12345,1133

如果一个数是 tobo 数,且这个数的平方是 tobo 数,则这个数是超级 tobo 数

\(1\)\(m\) 中有多少个超级 tobo 数

\(1<=m<=1e18\)

超级打表题

DFS 找到所有 tobo 数,然后再判断 tobo 数是不是超级 tobo 数,注意需要用 \(int128\)

DFS 不优化的话会跑的很慢,需要在本地跑得到结果,发现有235个超级 tobo 数

直接复制过来二分即可

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using lll=__int128;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;

vector<int> a(18);
vector<int> supertobo;

void check(){
    int val=0;
    int now=1;
    for(int i=a.size()-1;i>=0;i--){
        val+=a[i]*now;
        now*=10;
    }

    if(val==0) return;

    lll tmp=val;
    tmp*=tmp;

    vector<int> t;
    while(tmp){
        t.push_back(tmp%10);
        tmp/=10;
    }

    for(int i=0;i<t.size()-1;i++){
        if(t[i]<t[i+1]) return;
    }

    supertobo.push_back(val);
}

void dfs(int now){
    if(now>=18){
        check();
        return;
    }
    
    for(int i=(now==0?0:a[now-1]);i<=9;i++){
        a[now]=i;
        dfs(now+1);
    }

}

vector<int> sptobo{1,2,3,4,5,6,7,12,13,15,16,17,34,35,37,38,67,116,117,167,334,335,337,367,667,1667,3334,3335,
    3337,3367,3667,6667,16667,33334,33335,33337,33367,33667,36667,66667,166667,333334,333335,333337,333367,
    333667,336667,366667,666667,1666667,3333334,3333335,3333337,3333367,3333667,3336667,3366667,3666667,6666667,
    16666667,33333334,33333335,33333337,33333367,33333667,33336667,33366667,33666667,36666667,66666667,166666667,
    333333334,333333335,333333337,333333367,333333667,333336667,333366667,333666667,336666667,366666667,666666667,
    1666666667,3333333334,3333333335,3333333337,3333333367,3333333667,3333336667,3333366667,3333666667,3336666667,
    3366666667,3666666667,6666666667,16666666667,33333333334,33333333335,33333333337,33333333367,33333333667,
    33333336667,33333366667,33333666667,33336666667,33366666667,33666666667,36666666667,66666666667,166666666667,
    333333333334,333333333335,333333333337,333333333367,333333333667,333333336667,333333366667,333333666667,
    333336666667,333366666667,333666666667,336666666667,366666666667,666666666667,1666666666667,3333333333334,
    3333333333335,3333333333337,3333333333367,3333333333667,3333333336667,3333333366667,3333333666667,3333336666667,
    3333366666667,3333666666667,3336666666667,3366666666667,3666666666667,6666666666667,
    16666666666667,33333333333334,33333333333335,33333333333337,33333333333367,33333333333667,33333333336667,
    33333333366667,33333333666667,33333336666667,33333366666667,33333666666667,33336666666667,33366666666667,
    33666666666667,36666666666667,66666666666667,166666666666667,333333333333334,333333333333335,333333333333337,
    333333333333367,333333333333667,333333333336667,333333333366667,333333333666667,333333336666667,333333366666667,
    333333666666667,333336666666667,333366666666667,333666666666667,336666666666667,366666666666667,666666666666667,
    1666666666666667,3333333333333334,3333333333333335,3333333333333337,3333333333333367,3333333333333667,3333333333336667,
    3333333333366667,3333333333666667,3333333336666667,3333333366666667,3333333666666667,3333336666666667,3333366666666667,
    3333666666666667,3336666666666667,3366666666666667,3666666666666667,6666666666666667,16666666666666667,33333333333333334,
    33333333333333335,33333333333333337,33333333333333367,33333333333333667,33333333333336667,33333333333366667,
    33333333333666667,33333333336666667,33333333366666667,33333333666666667,33333336666666667,33333366666666667,
    33333666666666667,33336666666666667,33366666666666667,33666666666666667,36666666666666667,66666666666666667,
    166666666666666667,333333333333333334,333333333333333335,333333333333333337,333333333333333367,333333333333333667,
    333333333333336667,333333333333366667,333333333333666667,333333333336666667,333333333366666667,333333333666666667,
    333333336666666667,333333366666666667,333333666666666667,333336666666666667,333366666666666667,333666666666666667,
    336666666666666667,366666666666666667,666666666666666667};

void solve(){
	int m;
    cin>>m;
    int pos=upper_bound(sptobo.begin(),sptobo.end(),m)-sptobo.begin();
    cout<<pos<<endl;
}

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

    // dfs(0);
    

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}

A. Yet Another Tree Problem

题意:在树上选 \(1\)\(n\) 个相互没有祖先关系的节点,问选中的点集的点权和最大值

树上背包,设 \(f[i] [j]\) 表示从 \(i\) 的子树中选,选 \(j\) 个节点的最大总和

每次枚举子节点时,从前面的子节点中选 \(x\) 个,从当前子节点中选 \(y\) 个,选完当前子节点后,把当前子节点合并到前面的子节点中

注意实现细节,否则会被卡成 \(O(n^3)\)

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

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

    //f[i][j]: 从i的子树中选,选j个节点的最大总和
    vector<vector<int>> f(n+1,vector<int>(n+1,-1));

    for(int i=1;i<=n;i++){
        f[i][0]=0;
        f[i][1]=0;
    }

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

        vector<int> tmp(n+1,-1);
        tmp[0]=0;

        for(auto v:g[u]){
            if(v==pre) continue;

            //DP转移, f[u][i+j] = max(f[u][i+j] ,从前面的子节点中选i个,从v中选j的最大值)
            //每次转移完v后,需要讲v合并到"前面的子节点"中
            for(int i=0;i<=n && tmp[i]!=-1;i++){
                for(int j=0;j<=n && f[v][j]!=-1;j++){
                    f[u][i+j]=max(f[u][i+j],tmp[i]+f[v][j]);
                }
            }
            tmp=f[u];// tmp[i] 表示从前几个子节点中选i个的最大值,
            //每次合并子节点v时,需要保证v不会影响前面的值,而f[u][k]会实时变动
            //所以需要备份一边tmp数组
        }
        f[u][1]=max(f[u][1],w[u]);
    };

    dfs(dfs,1,0);

    for(int i=1;i<=n;i++){
        cout<<f[1][i]<<" ";
    }

    cout<<endl;
}

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

    int ct=1;
    cin>>ct;
    while(ct--){
        solve();
    }
    return 0;
}
posted @ 2025-08-14 19:17  LYET  阅读(14)  评论(0)    收藏  举报