编程语言
首页 > 编程语言> > 《2022牛客寒假算法基础集训营3》

《2022牛客寒假算法基础集训营3》

作者:互联网

C:首先我们可以知道重量为1的方案数就是重量为2的物品的数量,因为只有2 / 2 = 1可以影响它。

那么如果我们从小到大迭代的话,对于当前位置i,只能赋值2 * i才能影响当前位置,那么如果当前方案数的差为d,那么就还需要放d个2 * i。

这里要注意的是差值可能为负数。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e3 + 5;
const int M = 1e7 + 5;
const LL Mod = 1e9 + 7;
#define rep(at,am,as) for(int at = am;at <= as;++at)
#define INF 1e14
#define dbg(ax) cout << "now this num is " << ax << endl;
inline long long ADD(long long x,long long y) {
    if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
    return (x + y) % Mod;
}
inline long long MUL(long long x,long long y) {
    if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
    return x * y % Mod;
}
inline long long DEC(long long x,long long y) {
    if(x - y < 0) return (x - y + Mod) % Mod;
    return (x - y) % Mod;
}

int m;
LL a[N],dp[N];
vector<int> ans;
void solve() {
    cin >> m;
    rep(i,1,m) cin >> a[i];
    rep(i,1,m) {
        int d = ((a[i] - dp[i]) % Mod + Mod) % Mod;
        //while(((a[i] - dp[i]) % Mod + Mod) % Mod != 0) {
        rep(j,1,d) {
            int w = i * 2;
            ans.push_back(w);
            for(int j = m;j >= 1;--j) {
                if(j - w >= 0) dp[j] = ADD(dp[j],dp[j - w]);
                if(j - w / 2 >= 0) dp[j] = ADD(dp[j],dp[j - w / 2]);
            }
            if(w < N) dp[w] = ADD(dp[w],1);
            dp[w / 2] = ADD(dp[w / 2],1);
        }
        //}
    }
    if(ans.size() == 0) ans.push_back(2 * 1000);
    printf("%d\n",ans.size());
    for(auto v : ans) printf("%d ",v);
}   
int main() {
    // int _;
    // for(scanf("%d",&_);_;_--) {
        solve();
    //}
    //system("pause");
    return 0;
}
View Code

H:首先,选定一个点作为轴,那么它就旋转到了父节点处。

那么对于一棵子树,我们要把他的原来的根旋转上来,我们就只需要一直选定原来的根作为轴即可。

旋转的操作就是Splay就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e3 + 5;
const int M = 1e7 + 5;
const LL Mod = 998244353;
#define rep(at,am,as) for(int at = am;at <= as;++at)
#define INF 1e14
#define dbg(ax) cout << "now this num is " << ax << endl;
inline long long ADD(long long x,long long y) {
    if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
    return (x + y) % Mod;
}
inline long long MUL(long long x,long long y) {
    if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
    return x * y % Mod;
}
inline long long DEC(long long x,long long y) {
    if(x - y < 0) return (x - y + Mod) % Mod;
    return (x - y) % Mod;
}

int n;
vector<int> ans;
struct Splay {
    int sons[N][2],f[N],rt;
    bool vis[N];
    inline void Input() {
        rep(i,1,n) scanf("%d %d",&sons[i][0],&sons[i][1]),f[sons[i][0]] = f[sons[i][1]] = i,vis[sons[i][0]] = vis[sons[i][1]] = 1;
        rep(i,1,n) if(!vis[i]) rt = i;
        memset(vis,0,sizeof(vis));
    }
    inline bool chk(int x) {return sons[f[x]][1] == x;}
    inline void rotate(int x) {
        ans.push_back(x);
        int y = f[x], z = f[y], k = chk(x), w = sons[x][k^1];
        sons[y][k] = w;f[w] = y;
        sons[z][chk(y)] = x; f[x] = z;
        sons[x][k^1] = y; f[y] = x;
    }
    inline void splay(int x,int goal = 0) {
        while(!vis[f[x]] && f[x] != goal) {
            int y = f[x],z = f[y];
            if(!vis[z] && z != goal) {
                if (chk(x) == chk(y)) rotate(y);
                else rotate(x);
            }
            rotate(x);
        }
    }
}A,B;
void dfs(int rt) {
    B.splay(rt);
    B.vis[rt] = 1;
    if(A.sons[rt][0]) dfs(A.sons[rt][0]);
    if(A.sons[rt][1]) dfs(A.sons[rt][1]);
}
void solve() {
    scanf("%d",&n);
    A.Input();
    B.Input();
    dfs(A.rt);
    printf("%d\n",ans.size());
    for(auto v : ans) printf("%d\n",v);

}   
int main() {
    // int _;
    // for(scanf("%d",&_);_;_--) {
        solve();
    //}
    //system("pause");
    return 0;
}
View Code

 J:这题挺不错的。

首先我们把[L,R]都转到[0,R]上做处理。

那么就是说对于[0,R]上的点 % P之后在[l,r]里的数量。

那么就分为了k段的[0,P - 1]还有一段多出来的即R % P。

这里我们用线段合并

 

标签:rt,vis,int,牛客,sons,2022,ans,集训营,dp
来源: https://www.cnblogs.com/zwjzwj/p/15856319.html