文章目录
题目链接:https://ac.nowcoder.com/acm/contest/86639
写在前面
这是我打的第一次萌新联赛,总体来说题目不算太难,但以我现在的水平只能写出中等偏下的题目,还是得先打好基础,在往上拔高
回归正题
按题目的难度系数,分为A,H,K,I,F,G,D
本文按难度系数从上往下
A-造数
思路
签到题,我们将操作倒过来从n到0经过几个步骤即可
编程
void solve(){
int n;cin >> n;
int cnt=0;
if(n==0){
cout << 0 ;
return ;
}
if(n==1||n==2){
cout << 1 ;
return ;
}
while(n/2>0){
if(n%2){
n--;
cnt++;
}
n/=2;
cnt++;
}
cout << cnt << endl;
return ;
}
H-两难抉择
思路
签到题,找出序列中最大的数,然后让他乘以n即可,考虑特判当全是1的时候让其中一个1加上n才是最优
编程
void solve(){
int n;cin >> n;
int maxn=0;
int sum=0;
for(int i=1;i<=n;++i){
cin >> a[i];
sum+=a[i];
maxn=max(maxn,a[i]);
}
if(maxn==1){
cout << sum+n ;
}
else{
cout << sum-maxn+maxn*n;
}
return ;
}
K- 图上计数(Easy)
思路
简单的思维题,由于它可以删无数条边,那么我们只需要将所有边拆散然后均分为2堆连通块即可
编程
void solve(){
int n,m;
cin >> n >> m;
for(int i=1;i<=m;++i){
int u,v;
cin >> u >> v;
}
cout << (n/2)*(n-n/2) ;
return ;
}
I- 除法移位
思路
由于只有一个被除数,其他全是除数,因此我们优先考虑数列中最大的数做被除数,同时我们还要考虑最大的数位移的次数要小于等于t,否则就取次大的数,直到找到满足位移次数小于等于t的数即可
编程
bool cmp(PII x,PII y){
return x.fi>=y.fi;
}
void solve(){
int n,t;
vector<PII> b;
cin >> n >> t;
b.resize(n);
for(int i=0;i<n;++i){
cin >> a[i];
b[i]={a[i],i};
}
sort(b.begin(),b.end(),cmp);
for(int i=0;i<n;++i){
if(b[i].se==0){
cout << 0 ;
return ;
}
if(n-b[i].se<=t){
cout << n-b[i].se;
return ;
}
}
return ;
}
F- 两难抉择新编
思路
考点:暴力模拟,先将数列里所有数都进行异或处理,然后暴力模拟1到n/i的所有数即可,最后比较操作1和操作2大小,输出最大值即可
编程
void solve(){
int n;cin >> n;
int sum=0;
for(int i=1;i<=n;++i){
cin >> a[i];
sum^=a[i];
}
int maxn=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=n/i;++j){
int x=a[i];
int y=a[i];
x=x+j,y=y*j;
int k=sum,l=sum;
k^=a[i],l^=a[i];
k^=x;maxn=max(maxn,k);
l^=y;maxn=max(maxn,l);
}
}
cout << maxn ;
return ;
}
G-旅途的终点
思路
考点:反悔贪心,我们先开一个最大堆存储每次经过的路径,我们先不考虑释放神力k,每次经过国家都消耗生命值,当生命值小于等于0时,考虑反悔之前消耗生命值最多的一次,然后将栈顶出栈,若k次数用尽,则输出当前坐标减去1(不包含当前坐标),若最后全部通过则输出n
编程
void solve(){
int n,m,k;
cin >> n >> m >> k;
priority_queue<int> q;
for(int i=1;i<=n;++i){
cin >> a[i];
}
for(int i=1;i<=n;++i){
q.push(a[i]);
m-=a[i];
while(m<=0){
if(k<=0){
cout << i-1 << endl;
return ;
}
k--;
m+=q.top();
q.pop();
}
}
cout << n << endl;
return ;
}
D-小蓝的二进制询问
思路
考虑每一位二进制位的贡献。算出1到R的贡献减去1到L-1的贡献,就是L到R的贡献
从低位往高位枚举x的二进制位,简单枚举一下1到15的二进制可以发现,第0位是每2次出现一个1,第1位是每4次出现2个1,第2位是每8次出现4个1,可以看出,对于每一位,画红框的地方是每一位的循环节,第 k 位的循环节长度为2k+1,其中有2k个1,所以我们可以按位枚举,计算每一位上总共有多少个循环节和剩下非循环节中 1 的个数,因为这里是从 0 开始计算每一行的长度,所以实际计算时 x 需要加 1
编程
int mod=998244353;
int f(int x){
int ans=0,a=2;
x++;
while(x>=a/2){
ans=(ans+(x/a)*(a/2))%mod;//循环节里面1的个数
if(x%a!=0) ans=(ans+max(0ll,x%a-(a/2)))%mod;//非循环节1的个数
a*=2;
}
return ans;
}
void solve(){
int l,r;
cin >> l >> r;
cout << (f(r)-f(l-1)+mod)%mod << endl;
return ;
}