Loading

Codeforces Round #572 (Div. 2)

Codeforces Round #572 (Div. 2) 简要题解

A. Keanu Reeves

  1. 0,1数目不相等表示满足条件,答案为1
  2. 相等,则从第一个字符分割即可

B. Number Circle

  1. 排序,若满足\(a[n]<a[n-1]+a[n-2]\), 则可以构造,否则不可构造(这是显然的)
  2. 构造方法,假设\(a[n]\)放在位置\(k\),则\(a[n-1],a[n-2]\)放在\(k-1,k+1\),依次这样\(a[i]\)成对枚举放在\(k-t,k+t\) 位置;注意环状和奇偶讨论即可

C. Candies!

  1. \(a_i+a_j<20\) ,所以本质糖果数是区间和/10
  2. 前缀和处理即可

D1. Add on a Tree

  1. 题意: 每次可对叶子节点x,y之间的简单路径上的边权进行同一操作(add val);问是否每条边权都能取任意值;即任意边不会存在互相约束;
  2. 结论: 存在度为2,则不可能(显然);反之可行(给出构造)
  3. 考虑叶子节点x和普通节点u,下面证明可以实现x-u路径上所有边加任意值(假设y);

考虑u的子树(以u为根)的另外叶子节点\(l_1,l_2\),要求\(l_1,l_2,x\)不再\(u\)的同一个子树上。如下操作:
\(x-l_1 \quad +y/2\)
\(x-l_2 \quad +y/2\)
\(l_1-l_2 \quad -y/2\)
即可实现x-u路径+y(可画图观察)

  1. 有3可知,对于v-u边的权值可通过 x-v和x-u进行3中的处理

  2. D1只需2即可解,但3,4两点对D2很有帮助

D2. Add on a Tree: Revolution

解法

  1. 如 D1所只,我们已经掌握了如何构造更改u-v边权的操作
  • 均为非叶子节点,转化为x-u,x-v 需要6次操作
  • 均为叶子节点(实际是两个节点的情况)
  • u位叶子节点,需要3次操作

编程要点

  1. 至少需要获得非叶节点u的每个子树的一个叶子节点(以u为根);但一般dfs一次是固定的根
  2. 叶子节点x需要同时满足u,v的叶子节点,是u的v子树的叶子节点,而不是v的u子树叶子节点
  3. 自己的实现:
  • 以某一节点r为根求得非叶子节点的子树叶子节点集
  • 由于根的存在,某些非叶节点可能子树叶子节点集<3,那么从父节点的子树叶子节点集加入新的
  • 保证了至少有3个不同的叶子节点即很好处理了
  1. 下面是代码
code
#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O3")
#define ll long long
#define ull unsigned long long
#define db(x) cout<<#x"=["<<(x)<<"]"<<endl
#define CL(a,b) memset(a,b,sizeof(a))
#define mp make_pair
#define fast() ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define fr0(i,m) for(int i=0;i<m;i++)
#define fr1(i,m) for(int i=1;i<=m;i++)
//author:fridayfang
//date:19 7月 06
const double esp=1e-8;
const int mod=1e9+7;
const double pi=acos(-1);
const int inf=0x3f3f3f3f;
const int maxn = 1e3 + 5;
const int maxm = 1e6+5;
vector<pair<int,int>> G[maxn];//带权图
vector<pair<pair<int,int>,int>> edgs;
int par[maxn];//记录父亲
bool vis[maxn];
vector<int> leaf[maxn];//每次只选取子树的叶子节点leaf[]集的第一个
vector<pair<pair<int,int>,int>> ops;//存储操作
int n;
int root;
void dfs2(int u,int fa){
    par[u] = fa;
    if(G[u].size()==1){leaf[u].push_back(u);return ; }
    for(auto& tmp: G[u]){
        int t = tmp.first;
        if(t!=fa){dfs2(t,u);leaf[u].push_back(leaf[t][0]);}
    }
}
void pre(){
    dfs2(root,0);
    for(int i=1;i<=n;i++){
        if(G[i].size()>2&&leaf[i].size()==2){
            int u = par[i];
            for(auto& tmp: leaf[u]){
                if(tmp!=leaf[i][0]&&tmp!=leaf[i][1]){
                    leaf[i].push_back(tmp);break;
                }
            }
        }
    }
}

void addPath(int t,int v,int val){//表示对从t(v的某个叶子节点)-v 路径上全部加x
    int u = leaf[v][0], l1 = leaf[v][1], l2 = leaf[v][2];
    if(t==l1) swap(u,l1);// u=t
    if(t==l2) swap(u,l2);// u=t
    if(u!=t) swap(u,t);
    ops.push_back(mp(mp(u,l1),val/2));
    ops.push_back(mp(mp(u,l2),val/2));
    ops.push_back(mp(mp(l1,l2),-val/2));
}
void addEdge(int u,int v,int val){//对边u,v +x
    if(par[v]==u) swap(u,v);// keep v is father of u
    if(G[u].size()==1){addPath(u,v,val);return ;}
    if(G[v].size()==1){addPath(v,u,val);return ;}
    int t = leaf[u][0];
    addPath(t,v,val);
    addPath(t,u,-val);
}
void solve(){
    for(int i=1;i<=n;i++){
        root = i;
        dfs1(root,0);
    }
    for(int i=0;i<n-1;i++){
        int u = edgs[i].first.first, v = edgs[i].first.second, val = edgs[i].second;
        addEdge(u,v,val);
    }
    int opNum = ops.size();
    cout<<opNum<<endl;
    for(int i=0;i<opNum;i++){
        cout<<ops[i].first.first<<" "<<ops[i].first.second<<" "<<ops[i].second<<endl;
    }
}



int main(){
    fast();cin>>n;int u,v,val;
    if(n==2){
        cin>>u>>v>>val;
        cout<<"YES\n1\n"<<u<<" "<<v<<" "<<val<<endl;
        return 0;
    }
    for(int i=1;i<n;i++){
        cin>>u>>v>>val;
        G[u].push_back(mp(v,val)); G[v].push_back(mp(u,val));
        edgs.push_back(mp(mp(u,v),val));
    }
    bool OK = true; int j=-1;
    for(int i=1;i<=n;i++){
        if(G[i].size()==2) OK = false;
        if(G[i].size()>2) j = i;
    }
    if(!OK){cout<<"NO\n";return 0;}
    if(j==-1){return 0;}// no reach
    cout<<"YES\n";
    root = j; pre();
    solve();



    
    return 0;
}

E. Count Pairs

  1. 小技巧分离\(i,j\)即可,使得\(i,j\)同余;
code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define db(x) cout<<#x"=["<<(x)<<"]"<<endl
#define CL(a,b) memset(a,b,sizeof(a))
#define fast() ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define fr0(i,m) for(int i=0;i<m;i++)
#define fr1(i,m) for(int i=1;i<=m;i++)
//author:fridayfang
//date:19 7月 06
const double esp=1e-8;
const int mod=1e9+7;
const double pi=acos(-1);
const int inf=0x3f3f3f3f;
const int maxn = 3e5 + 5;
const int maxm = 1e6+5;
map<ll,ll> cnt;
ll n,p,k;
ll a[maxn];
ll pre(ll x){
    ll t = x;
    x = (x*x)%p;
    x = (x*x)%p;
    x = (x+p-(k*t)%p)%p;
    return x;
}
ll solve(){
    ll ans = 0;
    for(ll i=1;i<=n;i++){
        ll t = pre(a[i]);
        ans = (ans+cnt[t]);
        cnt[pre(a[i])]++;
    }
    return ans;
}

int main(){
    fast();
    cin>>n>>p>>k;
    for(ll i=1;i<=n;i++)cin>>a[i];
    ll res = solve();
    cout<<res<<endl;
    
    return 0;
}

F. Array Beauty

  1. 题意很重要:\(min_{1<=i<j<=n}{|a_i-a_j|}\); 而不是\(i,i+1\)
  2. \(q_i\)\(beauty>=i\)的方案数;那么\(\sum{q_i}\)即为所求,因为\(beauty==i\)的方案被统计了\(i\)
  3. \(dp[i][j]\)表述以\(a[j]\)结尾的长度为i的方案数;具体见代码
code
#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O3")
#define ll long long
#define ull unsigned long long
#define db(x) cout<<#x"=["<<(x)<<"]"<<endl
#define CL(a,b) memset(a,b,sizeof(a))
#define fast() ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define fr0(i,m) for(int i=0;i<m;i++)
#define fr1(i,m) for(int i=1;i<=m;i++)
//author:fridayfang
//date:19 7月 06
const double esp=1e-8;
const int mod=998244353;
const double pi=acos(-1);
const int inf=0x3f3f3f3f;
const int maxn = 1e3 + 5;
const int maxm = 1e6+5;

int a[maxn],n,k;
int dp[maxn][maxn],tsum[maxn][maxn];
//dp[i][j] 表示 长度为i以a[j]结尾的满足 beauty>=x 的 方案数
//tsum[i][j] 表是dp[i][1]+dp[i][2]+....dp[i][j]
int bound[maxn];// bound[i] = j 表示 a[i]...a[j] <= a[i]-x
inline int add(int x,int y){return (x+y)>=mod?(x+y-mod):(x+y);}
int solve(int x){//x>0
/*
    for (int i = 0; i <= k; i++) {
        for (int j = 0; j <= n; j++) {
            dp[i][j] = 0;
        }
    }
    */
    bound[0] = 0;
    for(int i=1;i<=n;i++){
        bound[i] = bound[i-1];
        while(a[i]-a[bound[i]+1]>=x) bound[i]++;
    }
    tsum[1][0]=0;
    for(int i=1;i<=k;i++){
        for(int j=i;j<=n;j++){
            if(i==1){dp[i][j] = 1; tsum[i][j] = (tsum[i][j-1]+dp[i][j]); continue;}
            dp[i][j] = tsum[i-1][bound[j]];
           // printf("db dp[%d][%d]=%d\n",i,j,dp[i][j]);
            tsum[i][j] = add(tsum[i][j-1],dp[i][j]);
        }
    }
    //db(tsum[k][n]);
    return tsum[k][n];
}
int main(){
    fast();cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    int ans = 0;
    int maxt = (a[n]-a[1])/(k-1);
    for(int t=1;t<=maxt;t++){
        ans = add(ans, solve(t));
    }
    cout<<ans<<endl;
    
    return 0;
}
posted @ 2019-07-07 02:17  fridayfang  阅读(412)  评论(0编辑  收藏  举报