Sum
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
给n个数A1,A2....An,你可以选择一个区间(也可以不选),区间里每个数x变成f(x),其中f(x)=(1890x+143)mod10007。问最后n个数之和最大可能为多少。
输入描述
输入有多组数据。 每组数据第一行包含一个整数n.(1≤n≤105) 第二行n个整数A1,A2....An.(0≤Ai≤104) 数据保证 ∑n≤106.
输出描述
对于每组数据输出一行答案.
输入样例
2 10000 9999 5 1 9999 1 9999 1
输出样例
19999 22033
暴力区间时间复杂度O(n^2),n<=10^5肯定会超时
方法一:
首先要先求出[i,j]区间x变为f(x)后的和sum1,以前的和sum,sum1-sum最大
可以先有一个数组把变化大小存着,再有dp求这个区间。
a[]数组表示就是已知数组,b[i]=f( a[i] )(0<i<=n)
如果最大的sum1-sum<0
答案的为a数组的前n项和
否者
a[1..l-1]和,b[l..r]和,a[l+1....n]和
三个和相加就是答案
#include
#include
#include
#include
using namespace std;
const int N = 100001;
int a[N];
int b[N];
int c[N];
int dp[N];
int f(int x)
{
return (1890*x+143)%10007;
}
void debug(int n, int a[])
{
for(int i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}
int main(void)
{
int n;
int i, j;
while(~scanf("%d", &n))
{
long long ans = 0;
for(i = 0; i < n; i++)
{
scanf("%d", &a[i]);
b[i] = f( a[i] );
c[i] = b[i] - a[i];
}
// debug(n, c);
// debug(n, b);
dp[0] = c[0];
int MAX = c[0];
int flag_x = 0;
for(i = 1; i < n; i++)
{
if(dp[i-1] < 0)
dp[i] = c[i];
else dp[i] = dp[i-1] + c[i];
if(MAX < dp[i])
{
MAX = dp[i];
flag_x = i;
}
}
int flag_y = flag_x;
for(i = flag_x; i >= 0; i--)
{
if(dp[i] < 0) break;
flag_y = i;
}
// printf("MAX=%d\n", MAX);
// printf("flag_y=%d \t flag_x=%d\n", flag_y, flag_x);
if(MAX <= 0)
{
for(i = 0; i < n; i++) ans += a[i];
}
else
{
for(i = 0; i < flag_y; i++)
ans += a[i];
for(i = flag_y; i <= flag_x; i++)
ans += b[i];
for(i = flag_x+1; i < n; i++)
ans += a[i];
}
printf("%I64d\n", ans);
}
return 0;
}
方法二:
联机算法
#include
int main(void)
{
int i;
int n;
while(~scanf("%d", &n))
{
long long sum = 0, maxn = 0;
long long MAX = 0;
int a;
for(i = 0; i < n; i++)
{
scanf("%d", &a);
sum += a;
int x = (1890*a+143)%10007 - a;
maxn += x;
if(maxn < 0) maxn = 0;
if(MAX < maxn) MAX = maxn;
}
printf("%I64d\n", sum+MAX);
}
return 0;
}