专栏文章
【题解】P6525 「Wdoi-1」蓬莱玉枝
P6525题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mimywmxm
- 此快照首次捕获于
- 2025/12/01 17:49 3 个月前
- 此快照最后确认于
- 2025/12/01 17:49 3 个月前
怀旧一下来补个题!出题人可爱喵/ka
选存在 的方案数等于总方案数 任意三项都满足 的方案数。然后后面这个东西在排序之后只需要满足相邻三项成立那么所有项都成立。
所以显然先对 升序排序。
然后先考虑总方案数如何计算。对于一个最大值为 的集合来说,前 个数可选可不选,所以这个集合的期望大小是 ,有 种可能,所以答案就是 。
然后考虑计算不合法的方案数。
考虑枚举集合的最大值和次大值进行 dp 转移,设 表示满足最大值为 ,次大值 的所有集合大小之和, 表示满足最大值为 ,次大值 的集合数量。
对于固定的 ,需要找到一个合法的位置 进行转移,合法的意义即满足 且 。
那么对于一个状态 ,要从其前驱状态 转移过来,它的大小之和 其前驱状态大小之和 其前驱数量 ,即 。
转移含义:所有前驱集合 都新加入一个 ,每个集合的大小 ,贡献的大小之和为 ;然后还要新计算一个集合 ,多贡献的大小为 。
同理有转移 。
那么如何确定 的位置呢?发现 肯定是随着 递增单调不增的,所以枚举 的同时双指针维护 的值即可。
根据我们设置的状态,转移结束之后还需要维护 。
实际上设置的 dp 状态就是为了维护前缀和。
时间复杂度 。
代码:
CPP#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;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...