比赛效果还行,过了两道题,继续加油
A Square Counting
简单思维
原题传送门
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define rep(i, a, b) for(int i = a; i <= b; ++ i)
const int N = 1e5 + 10;
int n, s;
int T;
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
//
scanf("%lld", &T);
while(T -- ){
scanf("%lld%lld", &n, &s);
int y = s / (n * n);
cout<<y<<endl;
}
return 0;
}
B Quality vs Quantity
原题传送门
简单思维
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define rep(i, a, b) for(int i = a; i <= b; ++ i)
const int N = 2e5 + 10;
int n;
int T;
int a[N];
int s[N];
signed main()
{
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
//
scanf("%lld", &T);
while(T -- ){
scanf("%lld", &n);
rep(i, 1, n){
scanf("%lld", &a[i]);
}
sort(a + 1, a + n + 1);
rep(i, 1, n){
s[i] = s[i - 1] + a[i];
}
if(n % 2 == 0){
if((s[n] - s[(n / 2) + 1]) - s[n / 2] > 0){
printf("YES\n");
}
else{
printf("NO\n");
}
}
else{
if((s[n] - s[(n / 2) + 1]) - s[(n / 2) + 1] > 0){
printf("YES\n");
}
else{
printf("NO\n");
}
}
}
return 0;
}
C Factorials and Powers of Two
原题传送门
算法流程:
先计算出所有小于1e12的阶乘数,将这些阶乘放入一个数组
利用二进制进行随机组合,将所有阶乘的组合形式都出现,让m减去这些组合形式的和
只有当m减去这些组合的和大于等于0时,m才有可能是被这些阶乘数构成的,此时s的1的个数存的就是阶乘的个数
所以此时得出二进制m剩余的1的个数和s中1的个数及此时的k值,循环所有阶乘数的组合,得出ans的最小值
#include<bits/stdc++.h>
using namespace std;
const long long N = 1e12 + 10;
#define int long long
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t -- ){
int n;
cin>>n;
int fe[15];
fe[0] = 1;
for(int i = 1; i < 15; i ++ ){
fe[i] = fe[i - 1] * i;
}
int ans = 1000;
for(int s = 0; s < (1 << 14); s ++ ){
int m = n;
for(int i = 0; i < 14; i ++ ){
if(s >> i & 1){
m -= fe[i + 1];
}
}
if(m >= 0) ans = min<int>(ans, __builtin_popcountll(s) + __builtin_popcountll(m));
}
cout<<ans<<endl;
}
return 0;
}
D Weight the Tree
树形DP,看了好几份代码和官方题解都没有搞明白,感谢xbx大佬的讲解
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5, M = 2 * N;
int e[M], ne[M], h[M], cnt;
struct Node{
int v, sum;
}f[N][2];
int T[N];
int dx[N];
void add(int a, int b){
cnt ++ ;
e[cnt] = b;
ne[cnt] = h[a];
h[a] = cnt;
}
void dfs(int a, int b){
//f的第一维是这个节点及其子树好节点的个数,第二维是该子树权值之和
//f[a][0]是把a节点认为是好顶点的情况,f[a][1]是不把a认为是好节点的情况
f[a][0] = {0, 1};//如果a不是好节点,则他的好节点个数为0(此时还没有计算他的子树,姑且认为是0),令a的权值为1,可使整个树的权值之和最小
f[a][1] = {1, dx[a]};//如果a是好节点,则他的好节点个数为1,权值就是他的度数
for(int i = h[a]; i; i = ne[i]){//遍历子树
int j = e[i];
if(j == b) continue;
dfs(j, a);
//如果认定a是好顶点就直接让a的好节点数量和权值之和加上他的该子节点j不是好节点的情况
f[a][1].v += f[j][0].v;
f[a][1].sum += f[j][0].sum;
//如果认定a不是好节点,就选择他的这个子节点j是/不是好节点两种情况中,好节点更多的情况加到a上
if(f[j][0].v > f[j][1].v || (f[j][0].v == f[j][1].v && f[j][0].sum < f[j][1].sum)){
f[a][0].v += f[j][0].v;
f[a][0].sum += f[j][0].sum;
}
else{
f[a][0].v += f[j][1].v;
f[a][0].sum += f[j][1].sum;
}
}
}
void build(int a, int b, bool ok){//建树,ok标识a节点是否被认定为好节点
if(ok) T[a] = dx[a];//如果a是好节点,则他的权值就是他的度,因为所有非好节点的权值都为1
else T[a] = 1;//如果a不是好节点,则a的权值为1
for(int i = h[a]; i; i = ne[i]){
int j = e[i];
if(j == b) continue;
if(ok) build(j, a, 0);
else{
if(f[j][1].v > f[j][0].v || (f[j][1].v == f[j][0].v && f[j][1].sum < f[j][0].sum)){
build(j, a, 1);
}
else{
build(j, a, 0);
}
}
}
}
//关键思想:在n!=2的情况下,任意两个相邻的节点只能有一个是好顶点
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
for(int i = 1; i < n; i ++ ){
int a, b;
cin>>a>>b;
dx[a] ++ ;
dx[b] ++ ;
add(a, b);
add(b, a);
}
if(n == 2){
cout<<"2 2"<<endl;
cout<<"1 1"<<endl;
return 0;
}
dfs(1, -1);
if(f[1][1].v > f[1][0].v || (f[1][0].v == f[1][1].v && f[1][0].sum > f[1][1].sum)){
cout<<f[1][1].v<<" "<<f[1][1].sum<<endl;
build(1, -1, 1);
}
else{
cout<<f[1][0].v<<" "<<f[1][0].sum<<endl;
build(1, -1, 0);
}
for(int i = 1; i <= n; i ++ ) cout<<T[i]<<" ";
cout<<endl;
}