杂题总结(主CF)
Move Back at a Cost
难度不高,容易有思路,但是不一定能想出正解。
首先容易想到结果一定是单调不降的,同时我们大体的思路是找到最值把它扔到最前面。(这一部分是自己思考的)。然后,深入研究(看题解)可知我们操作的顺序是有用的,我们将要加一的数放到最后的时候按从小到大排是最好的。所以一次操作后,数列一定是单调不降的两个序列,但是因为第二个的开头不一定比第一个的结尾高,所以还要调整大于第二开头加一的数。然后我们发现这两轮需要操作的数可以一起处理,按一定的顺序扔到后面即可。所以找两个最小值,确定修改的数,再排序即可。
#include<bits/stdc++.h>
using namespace std;
int t,n,a[100005],mn,emn,f[100005];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--)
{
cin>>n;
mn=emn=2e9;
for(int i=1;i<=n;i++){cin>>a[i];f[i]=0;}
for(int i=n;i>=1;i--)
{
if(mn>a[i])mn=a[i];
if(a[i]>mn)
{
a[i]++;f[i]=1;
emn=min(emn,a[i]);
}
}
for(int i=n;i>=1;i--)if(f[i]==0&&a[i]>emn)a[i]++;//第二轮寻找A数
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)cout<<a[i]<<" ";
cout<<"\n";
}
return 0;
}
CF2057C Trip to the Olympiad
基本是自己做出来的。
首先我们一定是想要某一位有一个或两个一,这样这一位可以贡献
#include <bits/stdc++.h>
using namespace std;
int t,l,r;
int getbit(int n,int i){return n&(1<<i);}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>l>>r;
bool flag=0;int now=0;
for(int i=29;i>=0;i--)
{
if(getbit(l,i)!=getbit(r,i))//比较任意这一位是否相同
{
int x=(1<<i)-1,y=(1<<i);//构建x:011111..y:10000....
x+=now,y+=now;//加上前缀
cout<<x<<' '<<y<<' ';
if(x==l||y==l)cout<<r<<'\n';
else cout<<l<<'\n';
flag=1;//标记
}
if(flag)break;
now+=(getbit(l,i))?(1<<i):0; //前缀
// cout<<i<<' '<<getbit(l,i)<<' '<<now<<'\n';
}
}
return 0;
}
CF1997C Even Positions
直接做出来的简单题。
读完题面就发现如果一个地方可以放右括号,就一定要放右括号,把右括号往后放一定是不优的(因为答案是右括号之和减左括号之和最小)。所以就记录一下前面有多少个左括号和右括号,能填就填右。
但是我们需要证明一下,按这样的规则是否合法,我们发现一定是合法的,不可能出现右括号比左括号多的情况(因为所有奇数被挖空)。
拓展:
如果去掉奇数和偶数的限制,规定一定的位置填左括号和右括号,是否有好做法?(还在思考)
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int t,n;
char s[N];
int main()
{
cin>>t;
for(int i=1;i<=t;i++)
{
cin>>n>>s+1;
int zk=0,yk=0,ans=0;
for(int j=1;j<=n;j++)
{
if(j&1)//奇数
{
if(zk<=yk)zk++,ans-=j;
else yk++,ans+=j;
}
else
{
if(s[j]=='(')zk++,ans-=j;
else yk++,ans+=j;
}
}
cout<<ans<<'\n';
}
return 0;
}
CF2004C Splitting Items
自己做出来的简单题,只要转换一下即可。
首先可以发现最优策略是从大到小排列,
本来已经做完了,结果我为了简便,将偶数上的加起来,奇数上的加起来,结果为max(偶-奇-k,0),错了。(因为没有考虑边界情况,有可能
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int t,n,k,a[N];
bool cmp(int x,int y){return x>y;}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>k;long long suma=0,sumb=0;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+n+1,cmp);
for(int i=2;i<=n;i+=2)
{
if(k>=a[i-1]-a[i])
{
k-=a[i-1]-a[i];
a[i]=a[i-1];
}
else
{
a[i]+=k;
break;
}
}
for(int i=1;i<=n;i+=2)suma+=a[i];
for(int i=2;i<=n;i+=2)sumb+=a[i];
cout<<suma-sumb<<'\n';
}
CF1967A Permutation Counting
自己做出来的简单题。
显然我们应该按
所以问题转化为最小值最大的问题,所以二分解决问题,即可。
拓展:还有实现更为复杂的线性做法,不过总时间复杂度瓶颈不在最后,所以时间复杂度不变。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
#define ll long long
const ll ee=1e18+10;
ll ans,t,n,k,a[N];
ll check(ll x)
{
ll cnt=0,sum=0;
for(int i=1;i<=n;i++)
{
if(a[i]<=x)cnt++,sum+=x-a[i];
if(sum>k)return ee;
}
return cnt-(k-sum);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
ll l=1,r=1e15+10,mid,sum=0;
while(l<=r)
{
mid=(l+r)>>1;ll tmp=check(mid);
if(tmp!=ee)ans=mid,sum=tmp,l=mid+1;
else r=mid-1;
}
cout<<ans*n-(n-1)+n-sum<<'\n';
}
return 0;
}
CF1312D Count the Arrays
一眼题。
很显然分界点一定是且相同的数一定不是最大值
所以总的方案数是
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10,mod=998244353;
int n,m;
int jc[N],inv[N],ans;
int ksm(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=res*x%mod;
y>>=1;
x=x*x%mod;
}
return res;
}
signed main()
{
cin>>n>>m;
jc[0]=inv[0]=1;
for(int i=1;i<=m;i++)jc[i]=jc[i-1]*i%mod;
inv[m]=ksm(jc[m],mod-2);
for(int i=m-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
if(n==2)
{
cout<<"0"<<'\n';
return 0;
}
int es=ksm(2,n-3);
cout<<(n-2)%mod*jc[m]%mod*inv[n-1]%mod*inv[m-n+1]%mod*es%mod<<'\n';
return 0;
}
CF1420D Rescue Nibel!
CF1288C Two Arrays
最开始想用dp,设
然后,发现感觉可以直接用组合数写式子。枚举
最后发现上面的
code
#include <bits/stdc++.h>
using namespace std;
const int N=1010,mod=1e9+7;
int n,m,sum[30][N],dp[30][N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)sum[0][i]=1;
for(int i=1;i<=2*m;i++)
{
for(int j=1;j<=n;j++)
dp[i][j]=sum[i-1][j];
for(int j=1;j<=n;j++)
sum[i][j]=(sum[i][j-1]+dp[i][j])%mod;
}
cout<<sum[2*m][n]<<'\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)