题解:P1982 [NOIP2013 普及组] 小朋友的数字
Yoimiya_miii · · 题解
题解:P1982 [NOIP2013 普及组] 小朋友的数字
思路
显然,这道题目需要先对于每一个节点求出最大子段和,做一遍 dp。
接下来,只需要线性扫描,求出每一个小朋友分数的前缀最大值即可。
时间复杂度
需要注意的是本题的数据范围,需要开 __int128。
AC Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
__int128 read() {
__int128 x = 0;
int w = 0;
char ch;
while (!isdigit(ch)) {
w |= ch == '-'; ch = getchar();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return w ? -x : x;
}
void out(__int128 x) {
if (x < 0) {putchar('-');x *= -1;}
if (x > 9) out(x / 10);
putchar(x % 10 + '0');
}
long long n;
__int128 p,a[maxn],dp[maxn],f[maxn],ans[maxn],anss;
inline __int128 abss(__int128 x){
if(x>=0)return x;
return -x;
}
int main(){
scanf("%lld",&n);
p = read();
for(long long i = 1;i <= n;i++) a[i] = read();
f[1] = a[1],ans[1] = a[1];
for(long long i = 2;i <= n;i++){
f[i] = max(a[i],f[i-1]+a[i]);
ans[i] = max(ans[i-1],f[i]);
}
if(n == 1){
out(ans[1]%p);
return 0;
}
dp[1] = ans[1],dp[2] = ans[1] + ans[1];
anss = max(dp[1],dp[2]);
for(long long i = 3;i <= n;i++) dp[i] = max(dp[i-1],dp[i-1]+ans[i-1]),anss = max(dp[i],anss);
if(anss < 0) printf("-");
__int128 o = abss(anss)%p;
out(o);
return 0;
}