Codeforces Round #774 (Div. 2)(ABCDE)

Codeforces Round #774 (Div. 2)(ABCDE)

总结:感冒十分难受,等等有时间写#775

A. Square Counting
在这里插入图片描述
题意:给定两个整数n和s,表示有元素集合 { 1 , 2 , 3... , n } ∪ { n 2 } \{1,2,3...,n\}∪\{n^2\} {123...,n}{n2},用在集合中挑选n+1个数(可重复)组成s,问其中会有多少个 n 2 n^2 n2
思路:好像直接拿s/(n*n)就行了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,s;

void solve(){
    scanf("%lld%lld",&n,&s);
    ll n2=n*n,nu=s/n2;
    printf("%lld\n",nu);
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

B. Quality vs Quantity
在这里插入图片描述题意:给定长度为n的序列,对其中数进行分类:红色、蓝色、无色。问是否存在情况,红色总和大于蓝色总和,同时红色个数小于蓝色个数
思路:从小到大排序,然后红色从后边取数,蓝色从前边取数,保证红色个数+1=蓝色个数,如果在使用个数<=n之前找到符号条件情况,就YES,否则NO。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+5;
ll n,a[N],pre[N];

void solve(){
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    for(ll i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
    ll l=2,r=1;
    while(l+r<=n){
        ll nul=pre[l];
        ll nur=pre[n]-pre[n-r];
        if(nur>nul){puts("YES");return;}
        l++,r++;
    }
    puts("NO");
}

int main(){
    int t;scanf("%d",&t);
    while(t--) solve();
}

C. Factorials and Powers of Two
在这里插入图片描述题意:给定数字n,最少使用一些不同的元素构成n,可以使用的元素为某数的阶层或2的几次方。不能构成输出-1
思路:首先肯定能构成,因为给定的数一定可以转成二进制数,我们总可以用一些2的几次方构成该数。为了最少,我们可以先记录有多少数的阶乘小于n,数不多,可以进行二进制枚举选取情况,最后如果n还有剩余,就全部用2的几次方去补齐。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,ans,len;
vector<ll>num;

void init(){
    ll nu=1;
    for(ll i=1;;i++){
        nu*=i;
        if(nu>1e12) break;
        num.push_back(nu);
    }
}

ll go(ll x,ll state){
    ll ned=0;
    for(ll i=0;i<len;i++){
        if((state>>i)&1) x-=num[i],ned++;
    }
    if(x<0) return 1e9;
    return ned+__builtin_popcountll(x);
}

void solve(){
    scanf("%lld",&n);
    ans=__builtin_popcountll(n);
    len=num.size();
    for(ll i=0;i<(1<<len);i++) ans=min(ans,go(n,i));
    printf("%lld\n",ans);
}

int main(){
    init();
    int t;scanf("%d",&t);
    while(t--) solve();
}

D. Weight the Tree

题意:给定一颗由n个节点构成的树,一个好节点的定义是其值等于所有与其相邻的节点的价值和。
输出最多有多少好节点,在此基础上保证总价值最小,同时输出每个节点的价值
思路:树形dp, d p [ p o s ] [ 0 / 1 ] dp[pos][0/1] dp[pos][0/1]表示以节点u为根,节点u是坏/好节点的子树好节点树,同时因为有得到节点值,我们需要构造出来,所以同时记录一下节点u的代价。
特例:n=2,好节点个数2,总价值2,每个节点价值1
除特例外,好节点和好节点不可能直接相连,所以 d p [ u ] [ 0 ] dp[u][0] dp[u][0]可以从 m a x ( d p [ v ] [ 0 ] , d p [ v ] [ 1 ] ) max(dp[v][0],dp[v][1]) max(dp[v][0],dp[v][1])转移过来,而 d p [ u ] [ 1 ] dp[u][1] dp[u][1]只能从 d p [ v ] [ 0 ] dp[v][0] dp[v][0]转移过来。

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int,int>PII;
const int N=2e5+5;
int n,w[N];
PII dp[N][2];
vector<int>edge[N];

void add(PII &a,PII b){
    a.x+=b.x;
    a.y+=b.y;
}

void dfs1(int u,int fa){
    dp[u][1]={1,-edge[u].size()};
    dp[u][0]={0,0};
    for(int i=0;i<edge[u].size();i++){
        int v=edge[u][i];
        if(v==fa)continue;
        dfs1(v,u);
        add(dp[u][1],dp[v][0]);
        add(dp[u][0],max(dp[v][0],dp[v][1]));
    }
}

void dfs2(int u,int fa,int type){
    if(type==0) w[u]=1;
    else w[u]=edge[u].size();
    for(int i=0;i<edge[u].size();i++){
        int v=edge[u][i];
        if(v==fa) continue;
        if(type==1) dfs2(v,u,0);
        else{
            if(dp[v][0]>dp[v][1]) dfs2(v,u,0);
            else dfs2(v,u,1);
        }
    }
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    if(n==2){
        puts("2 2");
        puts("1 1");
        return 0;
    }
    dfs1(1,0);
    if(dp[1][1]>dp[1][0]) dfs2(1,1,1);
    else dfs2(1,1,0);
    PII res=max(dp[1][0],dp[1][1]);
    printf("%d %d\n",res.x,n-res.y-res.x);
    for(int i=1;i<=n;i++) printf("%d%c",w[i],(i==n)?'\n':' ');
}

E. Power Board
在这里插入图片描述
题意+思路:

/*
一个n*m的网格,点(i,j)的值为i^j,问网格中一共有多少种元素
我们根据次方可知,例如i^4=(i^2)^2,所以我们可以只对所有的最简底数进行计算,看其有多少不同的指数
先得到最大指数是多少,随后化简底数形式,并遍历可能出现的情况,同时记忆化一下,因为当最大指数相同时,不同底数的贡献是一样的
例如底数x分别是2和3,两者初始的最大指数是3
x^1:    2    4     8     16              3    9    27     81    
x^2:    4    16    64    256             9    81   729    6561
x^3:    8    64    512   4096            27   729  19683  531441
发现不同底数,但当最大指数相同时,贡献都相同
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e6+6,M=2e7+1; //pow(2,20)>1e6
ll n,m,sum,num[N];
bool vis[N];
int used[M];

ll go(ll x){
    if(num[x]) return num[x];
    ll nu=0;
    for(ll i=1;i<=x;i++){
        for(ll j=1;j<=m;j++){
            if(used[i*j]!=x){
                used[i*j]=x;
                nu++;
            }
        }
    }
    return num[x]=nu;
}

int main(){
    scanf("%lld%lld",&n,&m);
    for(ll i=2;i<=n;i++){
        if(vis[i]) continue;
        vis[i]=true;
        ll use=1,now=i;
        while(now*i<=n){
            use++;
            now*=i;
            vis[now]=true;
        }
        sum+=go(use);
    }
    printf("%lld\n",sum+1);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值