I
思路
首先一个显然的dp方程是:设为过了天,选择了前个评分的最大价值。那么,其中,为区间的价值。
对进行预处理,考虑所给式子:
记为在中出现的次数,当且仅当时会为做出贡献(原因可以自己想一想)。因此先预处理每一个二进制位出现次数的前缀和,之后枚举左右端点,再枚举每一个二进制位的出现次数是否合法来计算。复杂度为。
预处理后dp复杂度为。
发现对于固定的,的值随减小而增加,而且每次都是增加一个不曾有过的的幂。所以最多有种取值。在状态转移的时候,如果,选择用转移一定不比用转移差,因为在天选了第个之后,再选一个不会让答案变小。所以我们可以预处理出所有发生变化的位置进行转移,复杂度降为。
另外注意每天至少选一个评分,所以转移的位置要进行判断(WA on 5)。
代码
#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define per(i,st,ed) for(int i=st;i>=ed;--i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
int __=0;
_=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
__=1;
ch=getchar();
}
while(isdigit(ch))
{
_=_*10+ch-48;
ch=getchar();
}
_=__?-_:_;
read(oth...);
}
template <typename T>
void Out(T _)
{
if(_<0)
{
putchar('-');
_=-_;
}
if(_>=10)
Out(_/10);
putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
Out(_);
putchar('\n');
OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
Out(_);
putchar(' ');
op(oth...);
}
/*#################################*/
const ll N=2005;
ll n,k;
ll a[N],f[N][N],sum[40][N],g[N][N];
vector<ll> ve[N];
void print()
{
rep(i,1,n)
{
rep(j,1,i)
op(g[j][i]);
en;
}
}
int main()
{
read(n,k);
rep(i,1,n)
read(a[i]);
rep(bit,1,34)
rep(i,1,n)
sum[bit][i]=sum[bit][i-1]+!!(a[i]&(1ll<<(bit-1)));
rep(R,1,n)
{
rep(L,1,R)
{
rep(bit,1,34)
if(sum[bit][R]-sum[bit][L-1] && sum[bit][R]-sum[bit][L-1]<R-L+1)
g[L][R]+=1<<(bit-1);
if(g[L][R]!=g[L-1][R])
ve[R].emplace_back(L-1);
}
ve[R].emplace_back(R);
}
rep(i,1,k)
rep(j,i,n)
for(auto it:ve[j])
if(it>=i)
f[i][j]=max(f[i][j],f[i-1][it-1]+g[it][j]);
OP(f[k][n]);
}
J
思路
把左括号看作,右括号看作,那么括号序列合法当且仅当任意前缀和且。
对翻转左右括号,对前缀和的影响可以分为三部分看:
- 对没有影响
- 对不同的位置影响不同
- 对影响相同。
先解决,考虑其中任意位置,设内左括号数目为,右括号数目为,有。
在翻转左右括号后,与互换,得到新的前缀和。
作差:。
。
那么每次翻转相当于对对前缀和整体取负数,然后加两倍的,用线段树维护即可。
对,直接减去,翻转完后在加上新的即可。
代码
#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define per(i,st,ed) for(int i=st;i>=ed;--i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
int __=0;
_=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
__=1;
ch=getchar();
}
while(isdigit(ch))
{
_=_*10+ch-48;
ch=getchar();
}
_=__?-_:_;
read(oth...);
}
template <typename T>
void Out(T _)
{
if(_<0)
{
putchar('-');
_=-_;
}
if(_>=10)
Out(_/10);
putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
Out(_);
putchar('\n');
OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
Out(_);
putchar(' ');
op(oth...);
}
/*#################################*/
#define lc p<<1
#define rc p<<1|1
const ll N=1e5+10;
string s;
ll n,m;
ll mini[4*N],maxi[4*N],rev[4*N],tag[4*N],sum[N];
void update(ll p)
{
maxi[p]=max(maxi[lc],maxi[rc]);
mini[p]=min(mini[lc],mini[rc]);
}
void build(ll p,ll l,ll r)
{
if(l==r)
{
mini[p]=maxi[p]=sum[l]=sum[l-1]+(s[l]=='('?1:-1);
return;
}
ll mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
update(p);
}
void rtag(ll p)
{
tag[p]=-tag[p];
swap(mini[p],maxi[p]);
mini[p]=-mini[p];
maxi[p]=-maxi[p];
rev[p]^=1;
}
void flag(ll p,ll val)
{
mini[p]+=val;
maxi[p]+=val;
tag[p]+=val;
}
void push_down(ll p)
{
if(rev[p])
{
rtag(lc);
rtag(rc);
rev[p]=0;
}
if(tag[p])
{
flag(lc,tag[p]);
flag(rc,tag[p]);
tag[p]=0;
}
}
void neg(ll p,ll l,ll r,ll al,ll ar)
{
if(al<=l && ar>=r)
{
rtag(p);
return;
}
ll mid=(l+r)>>1;
push_down(p);
if(al<=mid)
neg(lc,l,mid,al,ar);
if(ar>mid)
neg(rc,mid+1,r,al,ar);
update(p);
}
void add(ll p,ll l,ll r,ll al,ll ar,ll val)
{
if(al<=l && ar>=r)
{
flag(p,val);
return;
}
ll mid=(l+r)>>1;
push_down(p);
if(al<=mid)
add(lc,l,mid,al,ar,val);
if(ar>mid)
add(rc,mid+1,r,al,ar,val);
update(p);
}
ll query(ll p,ll l,ll r,ll al,ll ar)
{
if(al<=l && ar>=r)
return mini[p];
ll mid=(l+r)>>1,ret=1e17;
push_down(p);
if(al<=mid)
ret=min(ret,query(lc,l,mid,al,ar));
if(ar>mid)
ret=min(ret,query(rc,mid+1,r,al,ar));
return ret;
}
void print()
{
rep(i,1,n)
op(query(1,1,n,i,i));
en;
}
int main()
{
read(n,m);
cin>>s;
s=' '+s;
build(1,1,n);
ll l,r;
rep(i,1,m)
{
read(l,r);
ll _suml=0,sumr=query(1,1,n,r,r);
if(l!=1)
_suml=query(1,1,n,l-1,l-1);
neg(1,1,n,l,r);
add(1,1,n,l,r,2*_suml);
if(r!=n)
{
add(1,1,n,r+1,n,-sumr);
sumr=query(1,1,n,r,r);
add(1,1,n,r+1,n,sumr);
}
if(query(1,1,n,1,n)>=0 && query(1,1,n,n,n)==0)
puts("yes");
else
puts("no");
}
}