【题解】P6525 「Wdoi-1」蓬莱玉枝
题目传送门
怀旧一下来补个题!出题人可爱喵/ka
选存在
所以显然先对
然后先考虑总方案数如何计算。对于一个最大值为
然后考虑计算不合法的方案数。
考虑枚举集合的最大值和次大值进行 dp 转移,设
对于固定的
那么对于一个状态
转移含义:所有前驱集合
同理有转移
那么如何确定
根据我们设置的状态,转移结束之后还需要维护
实际上设置的 dp 状态就是为了维护前缀和。
时间复杂度
代码:
#include<bits/stdc++.h>
#define ll long long
#define back return
#define ri register int
#define ull unsigned ll
#define ld long double
using namespace std;
ll read()
{
ll 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*10+ch-'0';
ch=getchar();
}
back x*f;
}
const int p=20060723,N=5005;
ll n,tot,res,a[N],f[N][N],g[N][N],pw[N];
int main()
{
n=read();
for(ri i=1;i<=n;i++)
a[i]=read();
sort(a+1,a+n+1);
pw[0]=1;
for(ri i=1;i<=n;i++)
pw[i]=pw[i-1]*2%p;
tot=a[1];
for(ri i=2;i<=n;i++)
tot=(tot+a[i]*pw[i-2]%p*(i+1)%p)%p;
for(ri i=1;i<=n;i++)
{
res=(res+a[i])%p;
int k=i;
for(ri j=1;j<i;j++)
{
while(k>0&&a[k]>a[i]-a[j])
k--;
int l=min(k,j-1);
f[i][j]=(f[j][l]+g[j][l]+2)%p,g[i][j]=(g[j][l]+1)%p;
res=(res+a[i]*f[i][j]%p)%p;
f[i][j]=(f[i][j]+f[i][j-1])%p,g[i][j]=(g[i][j]+g[i][j-1])%p;
}
}
cout<<(tot-res+p)%p<<"\n";
back 0;
}