两道经典题目
差分,前缀和的逆操作
可以在m次区间+ - 修改后,O(n)的得到所有的值
排列不等式:
区间加减操作转换成选一个正数 -1 选 一个负数 +1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl = 5e5 + 10;
const int mod = 1e9 + 7;
int n, m, cas, k, cnt, tot, ans, top;
int a[maxl], b[maxl], c[maxl], s[maxl];
bool in[maxl];
ll ansmi, ansmx;
inline void prework()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
c[i] = b[i] = a[i] - a[i - 1];
}
c[n + 1] = b[n + 1] = -a[n];
}
inline ll sqr(ll x)
{
return x * x % mod;
}
inline void mainwork()
{
ansmi = 0;
for (int i = n + 1; i >= 1; i--)
if (b[i] < 0)
s[++top] = i;
for (int i = 1; i <= n; i++)
if (b[i] > 0)
{
while (b[i] > 0)
{
if (-b[s[top]] > b[i])
{
ansmi = (ansmi + sqr(s[top] - i) * b[i] % mod) % mod;
b[s[top]] += b[i];
b[i] = 0;
break;
}
else
{
ansmi = (ansmi + sqr(s[top] - i) * (-b[s[top]]) % mod) % mod;
b[i] += b[s[top]];
b[s[top]] = 0;
top--;
}
}
}
top = 0;
ansmx = 0;
for (int i = 1; i <= n + 1; i++)
if (c[i] > 0)
s[++top] = i;
else
{
while (c[i] < 0)
{
if (c[s[top]] > -c[i])
{
ansmx = (ansmx + sqr(i - s[top]) * (-c[i])) % mod;
c[s[top]] += c[i], c[i] = 0;
break;
}
else
{
ansmx = (ansmx + sqr(i - s[top]) * c[s[top]]) % mod;
c[i] += c[s[top]];
c[s[top]] = 0;
top--;
}
}
}
}
inline void print()
{
printf("%lld %lld", ansmi, ansmx);
}
int main()
{
int t = 1;
//scanf("%d",&t);
for (cas = 1; cas <= t; cas++)
{
prework();
mainwork();
print();
}
return 0;
}
Namomo contest 2 C.序列
问题有两个,变成相同数的最小操作数,和在最小操作数下,最终的可能数列个数