T2:分糖果
这个题完全不会啊。考虑序列的情况,容斥就是考虑有多少对相等关系,也就是有多少对等号,那么设 f [ i ] f[i] f[i]表示考虑到 i i i所有情况带上容斥系数的和,有 f [ i ] = ∑ j i − 1 f [ j ] × min ( a [ j + 1... i ] ) f[i]=\sum_j^{i-1}f[j]\times \min(a[j+1...i]) f[i]=∑ji−1f[j]×min(a[j+1...i]),那么有可以做到 O ( n 2 ) O(n^2) O(n2),用单调栈优化可以做到 O ( n ) O(n) O(n), f [ n ] f[n] f[n]就是答案。但是现在是环,还要考虑头和尾一样的贡献,直接搞不好考虑,因为不知道这一段的最小值,所以我们可以把最小值放到第一位,把这个环转一下,然后就可以算贡献了。
#include
using namespace std;
#define LL long long
#define pa pair
const int Maxn=1000010;
const int inf=2147483647;
const int mod=1000000007;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,a[Maxn],b[Maxn],mn=inf,pos,f[Maxn],sum[Maxn],sta[Maxn],top;
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
b[i]=read();
if(b[i]<mn)mn=b[i],pos=i;
}
for(int i=1;i<=n;i++)
{
a[i]=b[pos++];
if(pos==n+1)pos=1;
}
sta[top=1]=1;f[1]=a[1];sum[1]=a[1]-1;sum[0]=-1;
for(int i=2;i<=n;i++)
{
if(a[i]>=a[sta[top]])
{
f[i]=mod-f[i-1];
f[i]=(f[i]+(LL)f[i-1]*a[i]%mod+mod)%mod;
}
else
{
while(top&&a[i]<a[sta[top]])top--;
if(top)
{
f[i]=(LL)(sum[i-1]-sum[sta[top]-1]+mod)%mod*a[i]%mod;
if(sta[top]&1)f[i]=(f[i]-f[sta[top]]+mod)%mod;
else f[i]=(f[i]+f[sta[top]])%mod;
}
else f[i]=(LL)(1+sum[i-1])%mod*a[i]%mod;
if(i&1)f[i]=mod-f[i];
}
sta[++top]=i;
if(i&1)sum[i]=(sum[i-1]+f[i])%mod;
else sum[i]=(sum[i-1]-f[i]+mod)%mod;
}
int ans;
if(n&1)ans=mod-a[1];
else ans=a[1];
for(int i=1;i<=n;i++)
{
if((n-i)&1)ans=(ans-f[i]+mod)%mod;
else ans=(ans+f[i])%mod;
}
printf("%d",ans);
}
T3:灭虫
考虑DP。先按照 p p p排序, f [ i ] [ j ] f[i][j] f[i][j]表示到第 i i i个点,右端点为 j j j(离散化后)的最大覆盖距离。考虑转移,从 i i i转移到 i + 1 i+1 i+1,如果 i + 1 i+1 i+1是覆盖右边的,那么贡献十分简单,最主要是向左覆盖的贡献的计算。假如现在是 f [ i ] [ j ] f[i][j] f[i][j],更新某个 f [ k ] [ x ] f[k][x] f[k][x],要求 p k − l k p_k-l_k pk−lk至少覆盖到 p i + 1 p_{i+1} pi+1,而 i + 1 i+1 i+1到 k − 1 k-1 k−1的全部都向右覆盖,这个贡献是可以算出来的,要是覆盖的太远, j j j之前的贡献没有算上也没有关系,因为这样的已经在前面被算了,这样就可以做到 O ( n 3 ) O(n^3) O(n3),优化一下就是 O ( n 2 ) O(n^2) O(n2)了。看到这种比较复杂的不要害怕,只需要按部就班走就行了。
#include
using namespace std;
const int Maxn=3010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n;
struct Node{int p,l,r;}a[Maxn];
bool cmp(Node a,Node b){return a.p<b.p;}
int b[Maxn*3],lb=0,c=0;
int to[Maxn*3];
map<int,int>id;
int f[Maxn][Maxn*3],ans=-inf,mx1[Maxn][Maxn*3],mx2[Maxn][Maxn*3];
void cmax(int &x,int y){x=max(x,y);}
int main()
{
memset(mx1,-63,sizeof(mx1));
memset(mx2,-63,sizeof(mx2));
memset(f,0,sizeof(f));
n=read();
for(int i=1;i<=n;i++)
{
a[i].p=read(),a[i].l=read(),a[i].r=read();
b[++lb]=a[i].p-a[i].l;
b[++lb]=a[i].p;
b[++lb]=a[i].p+a[i].r;
}
sort(a+1,a+1+n,cmp);
sort(b+1,b+1+lb);
for(int i=1;i<=lb;i++)
{
if(i==1||b[i]!=b[i-1])c++;
to[c]=b[i];id[b[i]]=c;
}
a[0].p=0;
for(int i=0;i<=n;i++)
{
if(!i)
{
f[1][id[a[1].p+a[1].r]]=a[1].r;
f[1][id[a[1].p]]=a[1].l;
}
int mx=a[i].p;int ID=id[a[i].p-a[i].l];
for(int j=i-1;j>=0;j--)
{
if(a[i].p-a[i].l<=a[j+1].p)
{
cmax(f[i][id[mx]],mx+mx2[j][ID]);
cmax(f[i][id[mx]],mx+mx1[j][ID]-(a[i].p-a[i].l));
}
cmax(mx,a[j].p+a[j].r);
}
for(int j=0;j<=c;j++)
if(j)mx1[i][j]=max(mx1[i][j-1],f[i][j]);
else mx1[i][j]=f[i][j];
for(int j=c;j>=0;j--)
mx2[i][j]=max(mx2[i][j+1],f[i][j]-to[j]);
for(int j=0;j<=c;j++)
{
int p=id[a[i+1].p+a[i+1].r];
if(p>j)cmax(f[i+1][p],f[i][j]+a[i+1].p+a[i+1].r-max(a[i+1].p,to[j]));
cmax(f[i+1][j],f[i][j]);
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=c;j++)
cmax(ans,f[i][j]);
printf("%d",ans);
}