CSP2025模拟赛6
S+CSP2025模拟赛6
A. 劫富济贫
题意可以简化为在 次操作后, 使最穷的人最富,最富的人最穷。 所以考虑二分答案两个端点,把找到的答案减一下就可以了。 注意当 特别大是,差距可以来到 以内,所以特判一下。 代码:
#include
using namespace std;
#define int long long
const int N=5e5+5;
int k,n,lmax,rmin;
int a[N],qz[N],hz[N];
int checkl(int x){
int p=upper_bound(a+1,a+1+n,x)-a-1;
return p*x-qz[p];
}
int checkr(int x){
int p=lower_bound(a+1,a+1+n,x)-a;
return (qz[n]-qz[p-1])-(n-p+1)*x;
}
void findl(){
int l=a[1],r=a[n],mid,ans=0;
while(l>1;
if(checkl(mid)>1;
if(checkr(mid)>n>>k;
for(int i=1;i>a[i];
sort(a+1,a+1+n);
for(int i=1;i
`#include
using namespace std;
#define int long long
const int N=5e5+5;
int k,n,lmax,rmin;
int a[N],qz[N],hz[N];
int checkl(int x){
int p=upper_bound(a+1,a+1+n,x)-a-1;
return p*x-qz[p];
}
int checkr(int x){
int p=lower_bound(a+1,a+1+n,x)-a;
return (qz[n]-qz[p-1])-(n-p+1)*x;
}
void findl(){
int l=a[1],r=a[n],mid,ans=0;
while(l
mid=l+r>>1;
if(checkl(mid)1;
else r=mid-1;
}
lmax=ans;
}
void findr(){
int l=a[1],r=a[n],mid,ans=0;
while(l
mid=l+r>>1;
if(checkr(mid)1;
else l=mid+1;
}
rmin=ans;
}
signed main(){
freopen("rich2poor.in","r",stdin);
freopen("rich2poor.out","w",stdout);
cin>>n>>k;
for(int i=1;i>a[i];
sort(a+1,a+1+n);
for(int i=1;iqz[i]=a[i]+qz[i-1];
findl();
findr();
if(checkl(qz[n]/n)checkr((qz[n]+n-1)/n)
coutqz[n]%n?1:0)
}
else coutmax(0ll,rmin-lmax);
return 0;
}`
C++
B. 完美式子
可以发现: 也就是说括号嵌套其实等价于不嵌套。 那么就可以不考虑嵌套的情况。 剩下的就可以dp, 设 表示选到第 个数字,有 个括号,当前数字的正负为 时的最大答案。 代码:
#include
using namespace std;
#define int long long
const int N=1e5+5,M=25;
int n,m;
int a[N],dp[N][M][2],ans=INT_MIN;
signed main(){
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
cin>>n>>m;
for(int i=1;i>a[i];
if(n==1){
cout
`#include
using namespace std;
#define int long long
const int N=1e5+5,M=25;
int n,m;
int a[N],dp[N][M][2],ans=INT_MIN;
signed main(){
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
cin>>n>>m;
for(int i=1;i>a[i];
if(n==1){
couta[1]
return 0;
}
memset(dp,-0x3f,sizeof dp);
dp[2][0][0]=a[1]-a[2];
for(int i=3;i
for(int j=0;j
if(j) dp[i][j][1]=dp[i-1][j-1][0]+a[i];
dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]+a[i]);
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1])-a[i];
if(i==n) ans=max(ans,max(dp[i][j][0],dp[i][j][1]));
}
}
cout
return 0;
}`
C++
C. 线段
找到当先数之前相等的位置并标记下来,
找到左右端点的移动范围,
在反向循环统计答案。
代码:
#include
using namespace std;
#define int long long
const int N=3e3+5;
int n,ans;
int a[N],l[N],r[N];
int dp[N];
signed main(){
freopen("segment.in","r",stdin);
freopen("segment.out","w",stdout);
cin>>n;
for(int i=1;i>a[i];
int idx1=0,idx2=0;
for(int j=1;j
`#include
using namespace std;
#define int long long
const int N=3e3+5;
int n,ans;
int a[N],l[N],r[N];
int dp[N];
signed main(){
freopen("segment.in","r",stdin);
freopen("segment.out","w",stdout);
cin>>n;
for(int i=1;i
cin>>a[i];
int idx1=0,idx2=0;
for(int j=1;jif(a[i]==a[j]) r[idx1=j]=i;
for(int j=idx1;j;j--){
if(a[i]==a[j]) l[idx2=j]=i+1;
else l[j]=min(l[j],idx2);
}
for(int j=i-1;j;j--){
if(a[i]==a[j]) dp[j]=0;
else if(!r[j]) dp[j]=dp[j+1]+i-j;
else dp[j]=dp[l[j]]+(l[j]-j)*(i-r[j]);
ans+=dp[j];
}
}
cout
return 0;
}`
C++