组队训练记录(3):2021ICPC南京

2022.9.20

在这里插入图片描述
在这里插入图片描述
6题高罚时银牌中段。

A.Oops, It’s Yesterday Twice More

签到题 队友单开的

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
inline void solve(){
    int n, a, b; cin >> n >> a >> b;
    if(a - 1 <= n - a){
        for(int i = 1; i <= n - 1; i++) cout << 'U';
        if(b - 1 < n - b){
            for(int i = 1; i <= n - 1; i++) cout << 'L';
            for(int i = 1; i <= b - 1; i++) cout << 'R';
            for(int i = 1; i <= a - 1; i++) cout << 'D';
        } else {
            for(int i = 1; i <= n - 1; i++) cout << 'R';
            for(int i = 1; i <= n - b; i++) cout << 'L';
            for(int i = 1; i <= a - 1; i++) cout << 'D';
        }

    } else {
        for(int i = 1; i <= n - 1; i++) cout << 'D';
        if(b - 1 < n - b){
            for(int i = 1; i <= n - 1; i++) cout << 'L';
            for(int i = 1; i <= b - 1; i++) cout << 'R';
            for(int i = 1; i <= n - a; i++) cout << 'U';
        } else {
            for(int i = 1; i <= n - 1; i++) cout << 'R';
            for(int i = 1; i <= n - b; i++) cout << 'L';
            for(int i = 1; i <= n - a; i++) cout << 'U';
        }
    }
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

M. Windblume Festival

每个点对答案的贡献是 + 1 +1 +1 − 1 -1 1 ,判断全正和全负和 n = = 1 n==1 n==1 即可。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int n;
int a[1000005];
inline void solve(){
    cin>>n;
    int fg=0,sum=0,minn=1e9,maxn=-1e9;
    for(int i=1;i<=n ;i++){
        cin>>a[i];
        sum+=abs(a[i]);
        minn=min(minn,a[i]);
        maxn=max(maxn,a[i]);
        if(a[i]<=0)fg=1;
    }
    if(n==1){
        cout<<a[1]<<endl;
    }
    else if(minn>0){
        cout<<sum-2*minn<<endl;
    }
    else if(maxn<0){
        cout<<sum+2*maxn<<endl;
    }
    else{
        cout<<sum<<endl;
    }
}

signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    int t = 1; cin >> t;
    while(t--) solve();
    return 0;
}

C. Klee in Solitary Confinement

考虑 枚举答案。 开桶存权值对应所有点下标,线段树单点插入单点删除即可。(题解好像是 O ( n ) O(n) O(n) 的,但是nlogn暴力卡过去了)。

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 1e6 + 10;
namespace SegTree{
    #define ls rt << 1
    #define rs rt << 1 | 1
    #define lson ls, l, mid
    #define rson rs, mid + 1, r
    struct Info{
        int lmax, rmax, sum, ans;
        friend Info operator+ (Info a, Info b){
            return Info{
                max(a.lmax, a.sum + b.lmax),
                max(b.rmax, b.sum + a.rmax),
                a.sum+b.sum,
                max({a.ans,b.ans,a.rmax+b.lmax})
            };
        }
    } tree[N << 2];
    void push_up(int rt){ tree[rt] = tree[ls] + tree[rs]; }
    void update(int rt, int l, int r, int pos, int val){
        if(l == r){
            tree[rt] = Info{val, val, val, val};
            return;
        }
        int mid = l + r >> 1;
        if(mid >= pos) update(lson, pos, val);
        else update(rson, pos, val);
        push_up(rt);
    }
}
using SegTree::update;
vector<int> g[N << 1];
inline void solve(){
    int n, k, ans = 0; cin >> n >> k;
    for(int i = 1; i <= n; i++){
        int x; cin >>x;
        g[x + 1000000].emplace_back(i);
    }
    for(int i = 0; i <= 2000000; i++){
        ans = max((int)g[i].size(), ans);
    }
    if(k == 0){
       cout << ans << endl;
       return; 
    }
    int ed=min(2000000, 2000000 + k);
    for(int i = max(0, k); i <= ed; i++){
        if(!g[i].size()||!g[i-k].size())continue;
        for(auto &pos : g[i]){
            update(1, 1, n, pos, -1);
        }
        for(auto &pos : g[i - k]){
            update(1, 1, n, pos, 1);
        }
        int res = SegTree::tree[1].ans + g[i].size();
        ans = max(res, ans);
        for(auto &pos : g[i]){
            update(1, 1, n, pos, 0);
        }
        for(auto &pos : g[i - k]){
            update(1, 1, n, pos, 0);
        }
    }
    cout << ans;
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

D.Paimon Sorting

容易发现 ,对于新增的数 分为两种情况

小于等于前缀最大值,则交换的增加次数为前缀的大于自身的数的种类数
大于前缀最大值,暴力更新前缀最大值。

权值线段树维护即可。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e5 + 10;
int a[N];
namespace SegTree{
    #define ls rt << 1
    #define rs rt << 1 | 1
    #define lson ls, l, mid
    #define rson rs, mid + 1, r
    int tree[N << 2],fk[N<<2];
    void push_up(int rt){ fk[rt] = fk[ls] + fk[rs];tree[rt]=tree[ls]+tree[rs]; }
    void build(int rt, int l, int r){
        tree[rt] = fk[rt]=0;
        if(l == r) return;
        int mid = l + r >> 1;
        build(lson), build(rson);
    }
    void update(int rt, int l, int r, int pos, int val){
        if(l == r) return (void)(fk[rt] += val,tree[rt]=(fk[rt]!=0));
        int mid = l + r >> 1;
        if(mid >= pos) update(lson, pos, val);
        else update(rson, pos, val);
        push_up(rt);
    }
    int query(int rt, int l, int r, int L, int R){
        if(L > R) return 0;
        if(l >= L && r <= R) return tree[rt];
        int mid = l + r >> 1, ans = 0;
        if(mid >= L) ans += query(lson, L, R);
        if(mid < R) ans += query(rson, L, R);
        return ans;
    }
}
using SegTree::update;
using SegTree::query;
int dp[N];
inline void solve(){
    int n = 0; cin >> n;
    SegTree::build(1, 1, n);
    for(int i = 1; i <= n; i++) cin >> a[i], dp[i] = 0;
    int maxx = a[1],cnt=0,st=1;
    update(1, 1, n, a[1], 1);
    for(int i=2;i<=n;i++){
        update(1, 1, n, a[i], 1);
        if(a[i] <= maxx){
            dp[i] = dp[i - 1] + query(1, 1, n, a[i] + 1, n);
        } else {
            dp[i] = dp[st]+2;
            for(int j=st;j<i;j++){
                update(1, 1, n, a[j], -1);
            }
            for(int j=st+1;j<i;j++){
                dp[i]+=query(1, 1, n, a[j] + 1, n);
                update(1, 1, n, a[j], 1);
            }
            update(1,1,n,a[st],1);
            st=i;
        }
        maxx = max(maxx, a[i]);
    }
    for(int i = 1; i <= n; i++) cout << dp[i] << " \n"[i == n];
}
signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    int t = 1; cin >> t;
    while(t--) solve();
    return 0;
}

H. Crystalfly

树dp
f u f_u fu 表示以 u u u 为根结点,不算 u u u 的答案最大值, g u g_u gu 表示访问了 u u u 点之后立刻返回其父亲结点子树的最大值,暴力转移即可。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 10;
int n;
int a[100005],t[100005];
vector<int>p[100005];
int f[200005],g[200005];
int pre[100005],nxt[100005];
void dfs(int u,int fa){
    if(fa!=0)p[u].erase(find(p[u].begin(),p[u].end(),fa));
    if(!p[u].size()){
        g[u]=a[u];return;
    }
    int fk=0;
    for(auto v:p[u]){
        dfs(v,u);
        g[u]+=f[v];
        fk=max(fk,a[v]);
    }
    if(p[u].size()==1){
        f[u]=f[p[u][0]]+a[p[u][0]];
        g[u]+=a[u];
        return;
    }
    
    for(int i=0;i<p[u].size();i++){
        if(i==0){
            pre[i]=(t[p[u][i]]==3)?a[p[u][i]]:0;
        }
        else{
            pre[i]=pre[i-1];
            if(t[p[u][i]]==3)pre[i]=max(pre[i],a[p[u][i]]);
        }
    }

    for(int i=p[u].size()-1;~i;i--){
        if(i+1==p[u].size()){
            nxt[i]=(t[p[u][i]]==3)?a[p[u][i]]:0;
        }
        else{
            nxt[i]=nxt[i+1];
            if(t[p[u][i]]==3)nxt[i]=max(nxt[i],a[p[u][i]]);
        }
    }
    f[u]=g[u]+fk;
    
    for(int i=0;i<p[u].size();i++){
        int v=p[u][i];
        if(i==0){
            f[u]=max(f[u],g[u]+nxt[i+1]+g[v]-f[v]);
        }
        else if(i+1==p[u].size()){
            f[u]=max(f[u],g[u]+pre[i-1]+g[v]-f[v]);
        }
        else{
            f[u]=max(f[u],g[u]+max(pre[i-1],nxt[i+1])+g[v]-f[v]);
        }
    }
    g[u]+=a[u];
}
inline void solve(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        p[i].clear();
        f[i]=g[i]=0;
    }
    for(int i=1;i<=n;i++){
        cin>>t[i];
    }
    for(int i=1;i<n;i++){
        int u,v;cin>>u>>v;
        p[u].push_back(v);
        p[v].push_back(u);
    }
    dfs(1,0);
    cout<<f[1]+a[1]<<endl;
}

signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    int t = 1; cin >> t;
    while(t--) solve();
    return 0;
}

J. Xingqiu’s Joke

队友单切的 ,只知道是记搜。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

const int N=1e6+5;
int b[N], pr[N], tot=0;
void init()
{
    for(int i=2;i<=1e5;i++)
    {
        if(!b[i]) pr[++tot]=i;
        for(int j=1;pr[j]*i<=1e5;j++)
        {
            b[pr[j]*i]=1;
            if(i%pr[j]==0) break;
        }
    }
}
vector <int> g;
int sz[N];
unordered_map <int, int > mp; 
int dfs(int a, int d)
{
    if(mp[a*1e9+d]) return mp[a*1e9+d];
    if(a<=1) return 0;
    mp[a*1e9+d] = a-1;
    for(int x : g)
    {
        int tx=pr[x];
        if(!sz[x] || d%tx) continue;
        int dd = a%tx;
        sz[x]--;
        if(dd+2<tx-dd+1)
        {
            mp[a*1e9+d] = min(mp[a*1e9+d], dfs(a/tx,d/tx)+dd+1);
        }
        else if(dd+1>tx-dd+2)
        {
            mp[a*1e9+d] = min(mp[a*1e9+d], dfs(a/tx+1,d/tx)+tx-dd+1);
        }
        else 
        {
            mp[a*1e9+d] = min({mp[a*1e9+d], dfs(a/tx+1,d/tx)+tx-dd+1,dfs(a/tx,d/tx)+dd+1});
        }
        sz[x]++;
    }
    return mp[a*1e9+d];
}
inline void solve(){
    int a,b; cin>>a>>b;
    if(b<a) swap(a,b);
    int d=b-a;
    g.clear(); mp.clear();
    int tmp=d;
    for(int i=1;i<=tot;i++) sz[i]=0;
    for(int i=1;i<=tot;i++)
    {
        if(pr[i]*pr[i]>tmp) break;
        int cnt=0;
        while(tmp%pr[i]==0)
        {
            cnt++;
            tmp/=pr[i];
        }
        sz[i]=cnt;
        g.push_back(i);
    }
    if(tmp!=1) 
    {
        g.push_back(100000);
        sz[100000]=1;
        pr[100000]=tmp;
    }
    int ans=dfs(a,d);
    cout<<ans<<"\n";
}

signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    int t = 1;  cin >> t;
    init();
    //for(int i=1;i<=20;i++) cout<<pr[i]<<endl;
    while(t--) solve();
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值