Codeforces Round #774 (Div. 2)题解

A.Square Counting

链接
Luis has a sequence of 𝑛+1 integers 𝑎1,𝑎2,…,𝑎𝑛+1. For each 𝑖=1,2,…,𝑛+1 it is guaranteed that 0≤𝑎𝑖<𝑛, or 𝑎𝑖=𝑛2. He has calculated the sum of all the elements of the sequence, and called this value 𝑠.

Luis has lost his sequence, but he remembers the values of 𝑛 and 𝑠. Can you find the number of elements in the sequence that are equal to 𝑛2?

We can show that the answer is unique under the given constraints.

题意:有一个n+1长度的数组a 0<=ai<=n-1 或 ai=n^2 ,现在知道n的大小和数字元素的和s,问有几个ai=n ^2

题解:注意到(n-1)(n+1)<nn , 也就是说。不等于n^2的ai的和小于 n ^2,所以答案是 s/(n*n)

B.Quality vs Quantity

链接

比较简单

C.Factorials and Powers of Two

A number is called powerful if it is a power of two or a factorial. In other words, the number 𝑚 is powerful if there exists a non-negative integer 𝑑 such that 𝑚=2𝑑 or 𝑚=𝑑!, where 𝑑!=1⋅2⋅…⋅𝑑 (in particular, 0!=1). For example 1, 4, and 6 are powerful numbers, because 1=1!, 4=22, and 6=3! but 7, 10, or 18 are not.

You are given a positive integer 𝑛. Find the minimum number 𝑘 such that 𝑛 can be represented as the sum of 𝑘 distinct powerful numbers, or say that there is no such 𝑘.

题意:给定一个整数n,使用最少的不重复的2次幂或者阶乘数,使得这些数相加等于n。

注意到,这题一定有解,不难得出一个答案是n的二进制上1的位数,但是还有阶乘的存在;
又注意到,<=1e12的阶乘数仅有十五个,因此可以暴力枚举使用哪些阶乘数,然后再对剩下的数计算二进制上1的位数。
代码:

#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>
#define pb push_back
#define debug(x) cerr<<#x<<'='<<x<<'\n' 
#define debugg(x,y) cerr<<#x<<'='<<x<<','<<#y<<'='<<y<<'\n' 
#define FOR(a,b,c) for(int a=(b),a##_end=(c);a<=a##_end;++a)
#define ROF(a,b,c) for(int a=(b),a##_end=(c);a>=a##_end;--a)
#define FASTIO() cin.sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define rvs(s) reverse(s.begin(),s.end())
#define all(s) s.begin(),s.end()
#define sz(s) (int)(s.size())
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 200010 ,M = 1000010,mod = 998244353;const double eps = 1e-9;
ll qmi(ll,ll);
template<typename T>inline bool chkmin(T &x,const T &y){return y<x?x=y,1:0;}
template<typename T>inline bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}
ll n,m,k;
signed main()
{
    vector<ll> v;
    ll now = 6;
    for(ll i=4;;i++)
    {
        v.pb(now);
        now*=i;
        if(now>1e12) break;
    }
    int d = v.size();
    int T;
    read(T);
    while(T--)
    {
        read(n);
        int ans = 2e9;
        for(int i=0;i<(1<<d);i++)
        {
            ll sum = 0,cnt = 0;
            for(int j=0;j<d;j++)
                if(i>>j&1){
                    sum+=v[j],++cnt;
                }
            if(sum>n) continue;
            ll t = n-sum;
            for(int j = __lg(t);j>=0;j--)
                cnt+=t>>j&1;
            ans = min(ans,cnt);
        }
        cout<<ans<<'\n';
    }
    return 0;
}
ll qmi(ll a,ll b) {ll res=1;a%=mod;  for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}

D.Weight the Tree

You are given a tree of 𝑛 vertices numbered from 1 to 𝑛. A tree is a connected undirected graph without cycles.

For each 𝑖=1,2,…,𝑛, let 𝑤𝑖 be the weight of the 𝑖-th vertex. A vertex is called good if its weight is equal to the sum of the weights of all its neighbors.

Initially, the weights of all nodes are unassigned. Assign positive integer weights to each vertex of the tree, such that the number of good vertices in the tree is maximized. If there are multiple ways to do it, you have to find one that minimizes the sum of weights of all vertices in the tree.

题意:给定一个节点为n的树。当一个结点的权值等于周围结点的权值时,这个结点是good。权值由我们自己决定,求最多的good结点,若有多组答案,输出权值和最小的那个。

题解:当n==2时,两个结点都为good结点,权值都为1

当n>2时,一条边的两个结点不可能同时为good结点,于是就可以dp。我们可以让good结点等于他的度,不是good的结点权值为1,这样就能保证权值和最小。
定义数组PII f[i][2] 其中f[i][1]代表当根结点为i时且该结点为good结点,在子树中能形成的最多good结点及其最小权值。 同理f[i][1] 代表i不是good结点…
有上面的分析可知f[u][1] 只能从f[j][0]转移而来,f[u][0]可以从f[j][1]和f[j][0]中的较大者转移而来。

代码:

#include <bits/stdc++.h>
#include <unordered_map>
#include <unordered_set>
#define pb push_back
#define debug(x) cerr<<#x<<'='<<x<<'\n' 
#define debugg(x,y) cerr<<#x<<'='<<x<<','<<#y<<'='<<y<<'\n' 
#define FOR(a,b,c) for(int a=(b),a##_end=(c);a<=a##_end;++a)
#define ROF(a,b,c) for(int a=(b),a##_end=(c);a>=a##_end;--a)
#define FASTIO() cin.sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define rvs(s) reverse(s.begin(),s.end())
#define all(s) s.begin(),s.end()
#define sz(s) (int)(s.size())
#define int long long
using namespace std;
typedef long long ll;
const int N = 200010 ,M = 1000010,mod = 998244353;const double eps = 1e-9;
template<typename T>inline bool chkmin(T &x,const T &y){return y<x?x=y,1:0;}
template<typename T>inline bool chkmax(T &x,const T &y){return x<y?x=y,1:0;}
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}
int n,m,k;
int h[N],e[M],ne[M],idx,d[N];
struct node{
    int first,second;
    bool operator < (const node &W) const{
        if(first!=W.first)
            return first<W.first;
        return second>W.second;
    }
    bool operator > (const node &W) const{
        if(first!=W.first)
            return first>W.first;
        return second<W.second;
    }
    bool operator == (const node &W) const{
        if(first==W.first&&second==W.second)
            return 1;
        return 0;
    }
};
void add(int a, int b)
{
    e[idx] = b,ne[idx] = h[a], h[a] = idx ++ ;
}
node f[N][2];
void dfs(int u,int fa)
{
    f[u][1] = {1,d[u]},f[u][0] = {0,1};
    for(int i = h[u];~i;i = ne[i])
    {
        int j = e[i];
        if(j==fa) continue;
        dfs(j,u);
        f[u][1].first+=f[j][0].first;
        f[u][1].second+=f[j][0].second;
        node t = max(f[j][0],f[j][1]);
        f[u][0].first+=t.first;
        f[u][0].second+=t.second;
    }
}
int a[N];
void build(int u,int ans,int fa)
{
    if(ans==1)
    {
        a[u] = d[u];
        for(int i = h[u];~i;i = ne[i])
        {
            int j = e[i];
            if(j==fa) continue;
            build(j,0,u);
        }
    }
    else
    {
        a[u] = 1;
        for(int i = h[u];~i;i = ne[i])
        {
            int j = e[i];
            if(j==fa) continue;
            if(f[j][0]>f[j][1])
                build(j,0,u);
            else build(j,1,u);
        }
    }
        
    
}
signed main()
{
    memset(h,-1,sizeof h);
    read(n);
    if(n==2){
        puts("2 2\n 1 1");
        return 0;
    }
    for(int i=1;i<n;i++)
    {
        int a,b;
        read(a),read(b);
        add(a,b),add(b,a);
        d[a]++,d[b]++;
    }
    dfs(1,-1);
    node ans = max(f[1][0],f[1][1]);
    // cout<<f[1][0].first<<' '<<f[1][0].second<<endl;
    // cout<<f[1][1].first<<' '<<f[1][1].second<<endl;
    cout<<ans.first<<' '<<ans.second<<endl;
    if(f[1][0]>f[1][1])
        build(1,0,-1);
    else build(1,1,-1);
    for(int i=1;i<=n;i++)
        cout<<a[i]<<' ';
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值