Solution得等会。
Solution
-
(20\%,opt in {+,-})
这个水,无论从哪个点开始的值都是一样的,只要随便找一个点跑一遍输出既可。
(mathcal{O}(n)) -
(10\%,n le 1000)
这个照样水,枚举起点然后暴力算出其(F(x))值,取最大既可。
(mathcal{O}(n ^ 2)) -
(10\%,opt in {+, imes})
这有啥用啊,反正我是没想到
我瞎写的,不会真有人不会正解能拿这个部分分吧/jk/jk/jk -
(mathcal{O}(nsqrt{n}))做法
我们对边(E)集合分块,每个整块长度为(sqrt{n}),对每个块进行一下运算,变成一个(ax+b)的形式(也就是说一个数(x)进到这个块里运算的时候会变成(ax+b),相当于整个块的变换),跑一遍,总复杂度为(mathcal{O}(n))。
然后枚举起点,如果接下来的运算是一个完整的块,那么是(mathcal{O}(1))的,否则就暴力一下,最坏(mathcal{O}(sqrt{n}))。
显然是(mathcal{O}(nsqrt{n}))的复杂度,瓶颈在运算那边。
std使用了破环成链的方法,便于模拟。
# include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n;
struct edge
{
char opt;
long long x;
int soc;
}E[N << 1];
struct node
{
long long mul,add;
}a[N << 1];
int len,num;
int belong(int x)
{
if(x <= n) return (x - 1) / len + 1;
else
{
x -= n;
return (x - 1) / len + 1 + num;
}
}
int l[1005],r[1005];
void update(long long &x,int i)
{
if(E[i].opt == '+') x += E[i].x;
else x *= E[i].x;
return;
}
long long solve(int X)
{
int now = X,cnt = 0;
long long ans = 1;
int R = X + n - 1;
while(now <= R)
{
bool flag = 1;
int _l,_r;
if(now != l[belong(now)])
{
flag = 0;
_l = now;
}
else _l = l[belong(now)];
if(r[belong(_l)] > R)
{
_r = R;
flag = 0;
}
else _r = r[belong(_l)];
if(!flag)
{
for(int i = _l; i <= _r; i++)
{
update(ans,i);
}
now = _r + 1;
}
else
{
ans = ans * a[belong(_l)].mul + a[belong(_l)].add;
now = _r + 1;
}
}
return ans;
}
int main(void)
{
freopen("exin.in","r",stdin);
freopen("out1.out","w",stdout);
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
cin >> E[i].opt;
scanf("%lld",&E[i].x);
if(E[i].opt == '-')
{
E[i].opt = '+';
E[i].x = -E[i].x;
}
E[i].soc = i;
E[i + n] = E[i];
}
len = sqrt(n),num = (n - 1) / len + 1;
for(int i = 1; i <= num; i++)
{
l[i] = (i - 1) * len + 1;
r[i] = i * len;
a[i].mul = 1,a[i].add = 0;
}
r[num] = n;
for(int i = num + 1; i <= 2 * num; i++)
{
l[i] = l[i - num] + n;
r[i] = r[i - num] + n;
a[i].mul = 1,a[i].add = 0;
}
for(int i = 1; i <= num * 2; i++)
{
for(int j = l[i]; j <= r[i]; j++)
{
if(E[j].opt == '+')
{
a[i].add += E[j].x;
}
else
{
a[i].mul *= E[j].x;
a[i].add *= E[j].x;
}
}
}
long long ans = -1e9;
for(int i = 1; i <= n; i++)
{
long long _s = solve(i);
ans = max(ans,_s);
}
printf("%lld
",ans);
return 0;
}
- (mathcal{O}(nlog{n}))做法
by zps(LightningUZ).
其实差不多,破环成链,其实(F(x))就等于(E_x)到(E_{x + n})运算一遍,显然可以线段树维护求和。时间复杂度为(mathcal{O}(nlog{n}))。
对于两个区间((mul_1,add_1),(mul_2,add_2))合并:
[mul_2(mul_1 x + add_1) + add_2\
= mul_1 mul_2 x + mul_2 add_1 + add_2
]
所以新的(mul = mul_1mul_2,add = mul_2add_1+add_2)
# include <bits/stdc++.h>
using namespace std;
const int N = 100005;
struct node
{
long long mul,add;
}T[N << 2];
struct edge
{
char opt;
long long x;
}E[N << 1];
int n;
void build(int root,int l,int r)
{
T[root].mul = 1;
T[root].add = 0;
if(l == r)
{
if(E[l].opt == 'x')
{
T[root].mul *= E[l].x;
T[root].add *= E[l].x;
}
else
{
T[root].add += E[l].x;
}
return;
}
int mid = (l + r) >> 1;
build(root << 1,l,mid);
build(root << 1 | 1,mid + 1,r);
T[root].mul = T[root << 1].mul * T[root << 1 | 1].mul;
T[root].add = T[root << 1].add * T[root << 1 | 1].mul + T[root << 1 | 1].add;
if(T[root].mul == 0) T[root].mul = 1;
return;
}
node query(int root,int l,int r,int s,int t)
{
if(l <= s && t <= r)
{
return T[root];
}
int mid = (s + t) >> 1;
node L,R;
L.mul = 1,L.add = 0;
R.mul = 1,R.add = 0;
if(l <= mid) L = query(root << 1,l,r,s,mid);
if(r > mid) R = query(root << 1 | 1,l,r,mid + 1,t);
if(L.mul == 0) L.mul = 1;
if(R.mul == 0) R.mul = 1;
node ans;
ans.mul = 1,ans.add = 0;
ans.mul = L.mul * R.mul;
ans.add = L.add * R.mul + R.add;
// printf("lmul = %lld,ladd = %lld,rmul = %lld,radd = %lld
",L.mul,L.add,R.mul,R.add);
// printf("ansmul = %lld,ansadd = %lld
",ans.mul,ans.add);
return ans;
}
void print(int root,int l,int r)
{
int mid = (l + r) >> 1;
if(l != r) print(root << 1,l,mid);
if(l != r) print(root << 1 | 1,mid + 1,r);
printf("T[%d] : mul = %lld,add = %lld,l = %d,r = %d
",root,T[root].mul,T[root].add,l,r);
}
int main(void)
{
freopen("exin.in","r",stdin);
freopen("out2.out","w",stdout);
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
cin >> E[i].opt;
scanf("%lld",&E[i].x);
if(E[i].opt == '-')
{
E[i].opt = '+';
E[i].x = -E[i].x;
}
}
for(int i = 1; i <= n; i++)
{
E[i + n] = E[i];
}
for(int i = 1; i <= (n << 2); i++)
{
T[i].mul = 1,T[i].add = 0;
}
build(1,1,n + n);
// print(1,1,2 * n);
long long ans = -1e9;
for(int i = 1; i <= n; i++)
{
node A = query(1,i,i + n - 1,1,n * 2);
// printf("i = %d,mul = %lld,add = %lld
",i,A.mul,A.add);
ans = max(ans,A.mul + A.add);
}
printf("%lld
",ans);
return 0;
}
- (mathcal{O}(n))做法
by zps(LightningUZ).
单调区间求和trick,具体私聊zps.
总结:ZPS就是强啊!