Codeforces Round #774 (Div. 2)(ABCDE)
Posted 斗奋力努
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\\
1,2,3...,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;
以上是关于Codeforces Round #774 (Div. 2)(ABCDE)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #774 (Div. 2)(ABCDE)
Codeforces Round #774 (Div. 2)题解
Codeforces Round #774 (Div. 2)题解
Codeforces Round #436 E. Fire(背包dp+输出路径)