A
分析:
直接模拟,对于相邻的两个数,如果小的两倍还是比大的小,就乘2,同时贡献++。
代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;
int a[55];
int n;
int cal(int idx){
int maxv=max(a[idx],a[idx+1]);
int minv=min(a[idx],a[idx+1]);
int cnt=0;
while(minv*2<maxv) {minv*=2;cnt++;}
return cnt;
}
int main(){
int T; cin>>T;
while(T--){
cin>>n;
FOR(i,1,n) cin>>a[i];
int cnt=0;
FOR(i,1,n-1) cnt+=cal(i);
cout<<cnt<<endl;
}
return 0;
}
B
分析:
统计出 (mod3) 三种余数的个数。然后对小于 (n/3) 个数的多少进行分类讨论:
若个数为 (0) ,即最小的个数也是 (n/3) ,那么无需做任何操作。
若个数为 (1) ,那么要让两个多的给那个少的补上,并统计贡献。
若个数为 (2) ,那么要让多的给两个少的补上,并统计贡献。
即:
FOR(i,1,n){
cin>>a[i];
a[i]%=3;
cnt[a[i]]++;
}
int minv=INF;
FOR(i,0,2) minv=min(minv,cnt[i]);
if(minv==n/3){
cout<<0<<endl;
continue;
}
int res=0;
int cal=0;
FOR(i,0,2){
if(cnt[i]<n/3) cal++;
}
if(cal==1){
int idx;
FOR(i,0,2)
if(cnt[i]<n/3) idx=i;
res+=cnt[(idx+2)%3]-n/3 + 2*(cnt[(idx+1)%3]-n/3);
}
else if(cal==2){
int idx;
FOR(i,0,2)
if(cnt[i]>n/3) idx=i;
res+=n/3-cnt[(idx+1)%3] + 2*(n/3-cnt[(idx+2)%3]);
}
cout<<res<<endl;
代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;
int a[30005];
int cnt[3];
int main(){
int T; cin>>T;
while(T--){
SET0(cnt);
int n; cin>>n;
FOR(i,1,n){
cin>>a[i];
a[i]%=3;
cnt[a[i]]++;
}
int minv=INF;
FOR(i,0,2) minv=min(minv,cnt[i]);
if(minv==n/3){
cout<<0<<endl;
continue;
}
int res=0;
int cal=0;
FOR(i,0,2){
if(cnt[i]<n/3) cal++;
}
if(cal==1){
int idx;
FOR(i,0,2)
if(cnt[i]<n/3) idx=i;
res+=cnt[(idx+2)%3]-n/3 + 2*(cnt[(idx+1)%3]-n/3);
}
else if(cal==2){
int idx;
FOR(i,0,2)
if(cnt[i]>n/3) idx=i;
res+=n/3-cnt[(idx+1)%3] + 2*(n/3-cnt[(idx+2)%3]);
}
cout<<res<<endl;
}
return 0;
}
C
分析:
预处理出 ([1,1e4]) 的所有立方数,问题即转化为求 ([1,1e4]) 是否存在两个数满足它们的和为目标数。
代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=1e4+5;
set<ll> rec;
void init(){
FOR(i,1,N)
rec.insert((ll)i*i*i);
}
int main(){
init();
int T; cin>>T;
while(T--){
ll x; cin>>x;
bool ok=0;
for(auto i:rec){
if(rec.find(x-i)!=rec.end()) ok=1;
}
if(ok) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
D
分析:
分治,求出 ([1,n]) 中的最大值(根节点)所在下标 (root) ,然后继续处理 ([1,root-1]),([root+1,n]) 的最大值(对应的下标即为 (root) 的左右节点),并且分别连边(建树)。
建树后从根节点跑一遍dfs求出每个节点深度即可。
代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=205;
int n;
int a[N];
struct node{
int to,next;
}e[N];
int head[N],tot;
void add(int u,int v){e[tot].to=v;e[tot].next=head[u];head[u]=tot++;}
int d[N];
int solve(int l,int r){
if(l==r) return r;
if(l>r) return -1;
int root;
FOR(i,l,r){
if(a[i]==*max_element(a+l,a+1+r)){
root=i;
break;
}
}
int ls=solve(l,root-1);
int rs=solve(root+1,r);
if(ls!=-1) add(root,ls);
if(rs!=-1) add(root,rs);
return root;
}
void dfs(int u,int deg){
d[u]=deg;
if(head[u]==-1) return;
for(int i=head[u];~i;i=e[i].next){
int go=e[i].to;
dfs(go,deg+1);
}
}
int main(){
int T; cin>>T;
while(T--){
tot=0;
memset(head,-1,sizeof head);
cin>>n;
FOR(i,1,n) cin>>a[i];
solve(1,n);
int root;
FOR(i,1,n)
if(a[i]==n) root=i;
dfs(root,0); // for depth
FOR(i,1,n) cout<<d[i]<<' ';
cout<<endl;
}
return 0;
}
E
分析:
排序,找到一个断点 (idx) ,使得即便是 ([1,idx-1]) 的前缀和也比 a[idx]
小,那么 (idx) 之前的玩家必然无法获胜。最后记录一下 ([idx,n]) 的玩家编号即可。
代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=2e5+5;
struct node{
int id,v;
}a[N];
int b[N];
int n;
bool cmp(node a,node b){
return a.v<b.v;
}
ll s[N];
int main(){
int T; cin>>T;
while(T--){
cin>>n;
FOR(i,1,n){
cin>>a[i].v;
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
FOR(i,1,n){
s[i]=s[i-1]+a[i].v;
}
int idx=1;
DWN(i,n,1){
if(s[i-1]<a[i].v){
idx=i;
break;
}
}
cout<<n-idx+1<<endl;
int cnt=0;
FOR(i,idx,n) b[cnt++]=a[i].id;
sort(b,b+cnt);
FOR(i,0,cnt-1) cout<<b[i]<<' ';
cout<<endl;
}
return 0;
}
F
分析:
记录一下每个数对应的个数,然后从大到小进行排序,枚举断点 (i) , ([1,i]) 的数表示不需要删到 (0) , ([i+1,tot]) 的则全部删到 (0)。最后统计贡献并求最小值。
代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=2e5+5;
int n;
int buc[N];
int main(){
int T; cin>>T;
while(T--){
map<int,int> f;
cin>>n;
FOR(i,1,n){
int k; cin>>k;
++f[k];
}
int tot=0;
for(auto i:f)
buc[++tot]=i.second;
sort(buc+1,buc+1+tot,greater<int>());
int ans=INF;
FOR(i,1,tot)
ans=min(ans,n-i*buc[i]);
cout<<ans<<endl;
}
return 0;
}