为什么这个D这么难啊
首先显然有 v ≤ u v \le u v≤u,那么只要保证 v ≤ n v \le n v≤n
设 f [ n ] f[n] f[n]为 v ≤ n v \le n v≤n的合法点对和, v = a ⊕ b v=a \oplus b v=a⊕b
然后数位dp,考虑 a , b a,b a,b的最后一位,有同位0,一个1,和都是1三种情况,分别转移过来。
1和2,2和3两种情况显然是独立的,而1,3因为末位一样,似乎会重复。
假设会算重复,那么就要存在 a ⊕ b = c ⊕ d a \oplus b=c \oplus d a⊕b=c⊕d且 a + b + 1 = c + d a+b+1=c+d a+b+1=c+d ,显然不存在。
记忆化搜索即可。
code:
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const LL mod=1e9+7;
map<LL,LL> f;
LL n;
LL dfs(LL x)
{
if(x<0) return 0;
if(x==0) return 1;
if(f.count(x)) return f[x];
f[x]=(dfs(x>>1)+dfs((x-1)>>1)+dfs((x-2)>>1))%mod;
return f[x];
}
int main()
{
scanf("%lld",&n);
printf("%lld",dfs(n));
}
注意到只有-后面的括号才有效,且至多套两层括号,直接dp即可。
#include
#include
#include
#include
#define LL long long
using namespace std;
const LL inf=1LL<<60;
LL n,a[100010],f[100010][3];
char op[100010][2];
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++) scanf("%d %s",&a[i],op[i]);
scanf("%d",&a[n]);
f[1][0]=a[1];f[1][1]=f[1][2]=-inf;
for(int i=2;i<=n;i++)
if(op[i-1][0]=='+')
{
f[i][0]=max(f[i-1][0],f[i-1][1])+a[i];
f[i][1]=f[i-1][1]-a[i];
f[i][2]=f[i-1][2]+a[i];
}
else
{
f[i][0]=-inf;
f[i][1]=max(f[i-1][0],f[i-1][1])-a[i];
f[i][2]=max(f[i-1][1],f[i-1][2])+a[i];
}
printf("%lld",max(f[n][0],max(f[n][1],f[n][2])));
return 0;
}
先考虑一次询问怎么做,设 f [ i ] f[i] f[i]表示前 i i i位的答案,有方程式:
f [ i ] = m a x ( f [ i − 1 ] , f [ j ] + ( i − j ) ∗ ( i − j + 1 ) 2 − ( s u m [ i ] − s u m [ j ] ) ) f[i]=max(f[i-1],f[j]+\frac{(i-j)*(i-j+1)}{2}-(sum[i]-sum[j])) f[i]=max(f[i−1],f[j]+2(i−j)∗(i−j+1)−(sum[i]−sum[j]))
容易得到对策单调性是向左的,用单调栈维护斜率即可。
然后考虑修改。
设 f 1 f1 f1为前缀答案, f 2 f2 f2为后缀答案,假如修改位不选,那么就是 f 1 [ x − 1 ] + f 2 [ x + 1 ] f1[x-1]+f2[x+1] f1[x−1]+f2[x+1]
然后设 g [ x ] g[x] g[x]为强制选第 x x x为的最大值,此时答案为 g [ x ] − y + a [ x ] g[x]-y+a[x] g[x]−y+a[x]
怎么求 g g g?
分治,每层更新所有 m i d ≤ x ≤ r mid\le x\le r mid≤x≤r的 g g g,所以求出每个点为右端点,且左端点在左区间的答案,再取后缀最大值。最后反过来在做一次。
wa两个点,可能被卡精,不管了
code:
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
LL n,a[300010],f1[300010],f2[300010],sum[300010],g[300010],t[300010];
LL sta[300010],top=0;
LL Y(LL x,LL *f) {return 2*f[x]+x*x-x+2*sum[x];}
long double slope(LL j1,LL j2,LL *f) {return (long double)(Y(j1,f)-Y(j2,f))/(j1-j2);}
void pre(LL *f)
{
f[0]=0;sta[1]=0;top=1;
for(LL i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
for(LL i=1;i<=n;i++)
{
while(top>1&&slope(sta[top],sta[top-1],f)<=2*i) top--;
LL j=sta[top];
LL len=i-j;f[i]=max(f[i-1],f[j]+len*(len+1)/2-(sum[i]-sum[j]));
while(top>1&&slope(sta[top],i,f)>=slope(sta[top-1],sta[top],f)) top--;
sta[++top]=i;
}
}
void solve(LL l,LL r,LL *f1,LL *f2)
{
if(l==r) return;
LL mid=(l+r)/2;
sta[1]=l-1;top=1;
for(LL i=l;i<mid;i++)
{
while(top>1&&slope(sta[top],sta[top-1],f1)<=2*i) top--;
sta[++top]=i;
}
for(LL i=mid;i<=r;i++)
{
while(top>1&&slope(sta[top],sta[top-1],f1)<=2*i) top--;
LL j=sta[top];
LL len=i-j;t[i]=f1[j]+len*(len+1)/2-(sum[i]-sum[j])+f2[i+1];
}
for(LL i=r-1;i>=mid;i--) t[i]=max(t[i],t[i+1]);
for(LL i=r;i>=mid;i--) g[i]=max(g[i],t[i]);
solve(l,mid,f1,f2);solve(mid+1,r,f1,f2);
}
int main()
{
scanf("%lld",&n);
for(LL i=1;i<=n;i++) scanf("%lld",&a[i]);
pre(f1);reverse(a+1,a+n+1);pre(f2);reverse(a+1,a+n+1);reverse(f2+1,f2+n+1);
for(LL i=1;i<=n;i++) sum[i]=sum[i-1]+a[i],g[i]=-a[i];
solve(1,n,f1,f2);reverse(a+1,a+n+1);reverse(f1+1,f1+n+1);reverse(f2+1,f2+n+1);reverse(g+1,g+n+1);
for(LL i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
solve(1,n,f2,f1);reverse(a+1,a+n+1);reverse(f1+1,f1+n+1);reverse(f2+1,f2+n+1);reverse(g+1,g+n+1);
LL Q;scanf("%lld",&Q);
while(Q--)
{
LL x,y;scanf("%lld %lld",&x,&y);
printf("%lld\n",max(f1[x-1]+f2[x+1],g[x]-y+a[x]));
}
}