Codeforces Round #722 (Div. 2) A~E

比赛地址

A

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define SIS  std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;

const int N = 1e2+10;
int a[N];

int main()
{
    SIS;
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        for(int i=1;i<=n;++i) cin >> a[i];
        sort(a+1,a+1+n);
        int ans = 0;
        for(int i=n;i>1;i--){
            if(a[i]==a[1]) break;
            ans++;
        }
        cout << ans << '\n';
    }
    return 0;
}

B

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#define SIS  std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;

typedef long long ll;
const int N = 1e5+10;
ll a[N];
ll b[N];
ll mabs(ll x){
    return x<0?-x:x;
}
ll min(ll a,ll b){
    return a<b?a:b;
}
void solve(){
     int n;
        cin >> n;
        for(int i=1;i<=n;++i) cin >> a[i];
        sort(a+1,a+1+n);
        int pos = -1;
        for(int i=1;i<=n;++i){
            if(a[i]<=0){
                b[i]=a[i];
            }else{
                pos = i;
                break;
            }
        }
        if(pos==-1){
            cout << n << '\n';
            return;
        }
        //pos-1就是个数
        ll minn = (1ll<<50);
        for(int i=2;i<=pos-1;++i){
            minn=min(minn,mabs(b[i]-b[i-1]));
        }
        if(a[pos]<=minn) cout << pos << '\n';
        else cout << pos-1 << '\n';
}
int main()
{
    SIS;
    int t;
    cin >> t;
    while(t--){
        solve();
    }
    return 0;
}

C

比赛的时候想到DP了;

也想到状态转移肯定是要取上下限了;

可惜平时没怎么打树形dp,gg了…

现在来补


通过这题,有了些个人理解;

这题的树形dp就是先处理子节点然后回推父节点的一个过程;(线段树直呼内行,push_up…)

d p [ i ] [ j ] 表 示 当 前 在 节 点 i , j 表 示 取 上 界 或 者 下 界 dp[i][j]表示当前在节点i,j表示取上界或者下界 dp[i][j]ij

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <utility>
#include <cstdio>
#define SIS  std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;

typedef long long ll;

const int N = 1e5+10;

struct Node{
    int l,r;
}a[N];

ll dp[N][2];

struct Edge{
    int next,to;
}e[N<<1];
int head[N],cnt,vis[N];

void add(int u,int v){
    e[++cnt].to = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}
ll _abs(ll x){
    return x<0?-x:x;
}
void dfs(int cur){
    vis[cur]=1;
    for(int i=head[cur];i;i=e[i].next){
        int to = e[i].to;
        if(!vis[to]){
            dfs(to);
            //树形dp 先搞子节点 再回推父节点
            dp[cur][0] += max(_abs(a[to].l-a[cur].l)+dp[to][0],dp[to][1]+_abs(a[to].r-a[cur].l));
            dp[cur][1] += max(_abs(a[to].l-a[cur].r)+dp[to][0],dp[to][1]+_abs(a[to].r-a[cur].r));
        }
    }
}
int main()
{
    SIS;
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        vis[0]=head[0]=cnt=0;
        for(int i=1;i<=n;++i){
            vis[i]=head[i]=0;
            auto &x = a[i];
            cin >> x.l >> x.r;
        }
        for(int i=1,u,v;i<=n-1;++i){
            cin >> u >> v;
            add(u,v);
            add(v,u);
        }
        for(int i=0;i<=n+5;++i){
            dp[i][0]=dp[i][1]=0;
        }
        dfs(1);
        cout << max(dp[1][0],dp[1][1]) << endl;
    }
    return 0;
}

D

首先考虑长度相等的情况;

在这里插入图片描述
接着考虑包含的情况

在这里插入图片描述
在这里插入图片描述
可以发现,当我们外面的大圈确定好后;

里面就是已经推出的状态了;

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <utility>
#include <cstdio>
#define SIS  std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;

typedef long long ll;

const int N = 1e6+10;

int factor[N];//factor(i) 表示i这个数的因子个数,比如factor(8)={1,2,4,8}=4
ll f[N];
ll sum;
const ll MOD = 998244353;

int main()
{
    SIS;
    int n;
    cin >> n;
    for(int i=1;i<=n;++i){
        for (int j=i;j<=n;j+=i) {
            factor[j]++;
        }
    }
    sum=f[1]=1;
    for(int i=2;i<=n;++i){
        f[i]=(sum+factor[i])%MOD;
        sum=(sum+f[i])%MOD;
    }
    cout << f[n] << '\n';
    return 0;
}

可以通过线性筛 搞到 O ( n ) O(n) O(n)

如下

线性筛获取约数个数点我

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <utility>
#include <cstdio>
#define SIS  std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;

typedef long long ll;

const int N = 1e6+10;

int factor[N];//factor(i) 表示i这个数的因子个数,比如factor(8)={1,2,4,8}=4
int d[N];
ll f[N];
ll sum;
int prime[N];
bool noprime[N];
const ll MOD = 998244353;

int main()
{
    SIS;
    int n,tot=0;
    cin >> n;
    factor[1]=1;
    for(int i=2;i<=n;++i){
        if(!noprime[i]){
            d[i]=1;
            factor[i]=2;
            prime[++tot] = i;
        }
        for(int j=1;i*prime[j]<=n&&j<=tot;++j){
            noprime[i*prime[j]] = 1;
            if(i%prime[j]==0){
                factor[i*prime[j]]=factor[i]/(d[i]+1)*(d[i]+2);
                d[i*prime[j]] = d[i]+1;
                break;
            }
            factor[i*prime[j]]=factor[i]*2;
            d[i*prime[j]]=1;
        }
    }
    sum=f[1]=1;
    for(int i=2;i<=n;++i){
        f[i]=(sum+factor[i])%MOD;
        sum=(sum+f[i])%MOD;
    }
    cout << f[n] << '\n';
    return 0;
}

E

思路:对树1跑dfs,对树2用数据结构维护;

Code

#include <iostream>
#include <vector>
#include <set>

using namespace std;

const int N = 3e5+10;

typedef pair<int,int> pii;

int in[N],out[N],timer,ans;
vector<int> v1[N];
vector<int> v2[N];

set<pii> s;

//构造dfs序
void dfs1(int u){
    in[u]=++timer;
    for(auto i : v2[u]){
        dfs1(i);
    }
    out[u]=timer;
}
/*
首先找第一个>in[u]的节点
如果找到了且这个点是u的子孙,那么我们不要u,选择子孙;
如果不存在这样一个点的in[v]>in[u],那么直接添加u
如果找到的点in[v]>in[u],但他不是子孙;那么我们找in[u]的祖先;
如果存在in[u]的祖先,那么把他干掉;否则直接加in[u]
*/
int add(int u){
    auto it = s.upper_bound({in[u],u});
    if(it!=s.end()&&out[it->second]<=out[u]) return -2;//子孙
    if(it==s.begin()) return -1;//不存在祖先和子孙
    --it;//试图寻找祖先
    int tmp = it->second;
    //如果是祖先的话 那么out时间≥out(u)
    if(out[tmp]<out[u]) return -1;//不存在祖先和子孙
    //存在祖先
    s.erase(it);
    return tmp;//返回祖先的标记 用于回溯
}
void dfs2(int u){
    int ret = add(u);
    if(ret!=-2){
        s.insert({in[u],u});
    }
    ans=max(ans,(int)s.size());
    for(auto i : v1[u]){
        dfs2(i);
    }
    //回溯
    if(ret!=-2){
        s.erase({in[u],u});
        if(ret!=-1) s.insert({in[ret],ret});
    }
}

int main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        for(int i=1;i<=n;++i){
            v1[i].clear();
            v2[i].clear();
        }
        ans = timer = 0;
        s.clear();
        for(int i=2,father;i<=n;++i){
            cin >> father;
            v1[father].push_back(i);
        }
        for(int i=2,father;i<=n;++i){
            cin >> father;
            v2[father].push_back(i);
        }
        dfs1(1);
        dfs2(1);
        cout << ans << '\n';
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值