题解 P1982 【小朋友的数字】
本蒟蒻居然能在机房里打出绿题正解当然要纪念一下
首先读题,这题题面极其凌乱(莫非是考个语文舒缓一下选手心情??)我连样例都看了好几遍才懂
特征值就是排在某个小朋友(包括他自己)之前所有小朋友中连续一段的数字总和的最大值,等于求在某个数之前(包含自己)的最大连续子段和,则可以先DP求出这些小朋友的特征值,然后跑一遍求出分数最后%即可
但是就这样跑只能拿80分???第一遍交的代码如下
#include<bits/stdc++.h>
using namespace std;
long long maxn=0xcf,n,m,i,p,ans=0,b[1000001],dp[1000001],f[1000001],a[1000001];
bool tag=0,bj=0;
int main(){
memset(f,0xcf,sizeof(f));
scanf("%lld%lld",&n,&p);
for(i=1;i<=n;i++){
scanf("%lld",&a[i]);
maxn=max(maxn,a[i]);
}
if(maxn<0){
cout<<"-"<<abs(maxn)%p;
return 0;
}
if(maxn==0){
cout<<"0";
return 0;
}
f[1]=a[1];
dp[1]=f[1];
maxn=a[1];
m=1;
for(i=2;i<=n;i++) f[i]=max(f[i-1]+a[i],a[i]),dp[i]=max(dp[i-1],f[i]);
for(i=1;i<=n;i++) b[i]=a[i];
ans=f[1];
b[2]=a[1]+f[1];
if(b[2]>b[1]) maxn=b[2],m=2;
for(i=3;i<=n;i++){
b[i]=max(b[m]+dp[m],b[i-1]+dp[i-1]);
if(b[i]>maxn) maxn=b[i],m=i;
}
for(i=1;i<=n;i++) ans=max(ans,b[i]);
if(ans<0){
cout<<"-"<<abs(ans)%p;
return 0;
}
cout<<ans%p;
return 0;
}
因为分数加到最后可能很大,中间又是max计算,取模了最大值就出了问题,那怎么办嘞?
再仔细想想(胡乱猜测),分数序列要么是单调递减的,要么是单调递增的,要么先递减后递增,所以答案应该在分数序列首或尾(需要打个标记记录是否有递增序列,如果有,那分数应出现在最后,如果单调递减,那分数最大值就为b[1])
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
long long n,i,p;
long long ans=0;
long long maxn=0xcf;
//b数组是最终分数,f是以i为末尾的最大连续子段和,dp是i之前的最大连续子段和(即题目中的特征值),a是小朋友手上的数字
long long b[1000001],dp[1000001],f[1000001],a[1000001];
bool tag=0; //标记
inline long long read(){ //快读优化(机房老爷机不加快读优化就T了一个点....)
long long x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
int main(){
memset(f,0xcf,sizeof(f)); //先将f数组赋为无限小
n=read(),p=read(),a[1]=read();
f[1]=a[1];
dp[1]=f[1];
b[1]=a[1];
ans=f[1];
for(i=2;i<=n;i++){ //dp
a[i]=read();
f[i]=max(f[i-1]+a[i],a[i]);
dp[i]=max(dp[i-1],f[i]);
}
b[2]=a[1]+f[1];
if(b[2]>b[1]) ans=b[2],tag=1; //比较b[2]和b[1]是否出现递增序列,若出现tag=true;
for(i=3;i<=n;i++){
if(dp[i-1]<0){ //如果i-1的特征值小于0,那加上会使答案变小不如不加
b[i]=b[i-1];
continue;
}
b[i]=b[i-1]+dp[i-1];
if(b[i]>b[1]) tag=1; //同上
if(tag==1) b[i]%=p; //重点:由于序列递增,那么b[i]>=b[i-1]所以不需要max比较,直接更新取模即可
ans=b[i];
}
if(tag==0){ //若序列单调递减,则b[1]就是最大值
printf("%lld",b[1]);
return 0;
}
printf("%lld",ans); //若序列存在递增,那么输出ans即可
return 0; //完结撒花
}
唔,又要开学了,又要面对语数外物化生...