AGC049D
题意:计数 \(\{a_n\geqslant 0\}\) 使得 \(\sum a=m\) 且 \(2a_i\leqslant a_{i-1}+a_{i+1}\)
瞎扯:貌似是之前的讲课题。首先想到查分 \(d'\),条件 \(2\) 等价于 \(d'\) 递增。有性质:只有最后 \(\sqrt m\) 个位置 \(d'\) 有值。不妨再差分一次 \(d\),就去掉了递增的条件。但是我发现,我只能做 \(a\) 递增的情况/kk
正解:考虑那个我会的情况,其实就是做完全背包。应该要敏感地发现完全背包计数是乘一个多项式,也非常好撤销。由于它一定是一些递减、一段平的、一些递增,我们不妨枚举第一个最小值的位置,对前对后都做完全背包就行,我们每次也只用乘以一个差项即可。时间复杂度还是 \(O(m\sqrt m)\)
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
#define ll long long
int n,m,f[maxn],ans;
inline void A(ll x){for(ll i=x;i<=m;i++)f[i]=(f[i]+f[i-x])%mod;}
inline void D(ll x){for(ll i=m;i>=x;--i)f[i]=(f[i]-f[i-x])%mod;}
int main(){
n=read(),m=read();f[0]=1;A(n);
for(int i=2;i<=n;i++)A(1ll*(n-i+1)*(n-i+2)/2);
for(int i=1;i<=n;i++){
if(1ll*i*(i-1)/2<=m)ans=(ans+f[m-1ll*i*(i-1)/2])%mod;
A(1ll*i*(i+1)/2),D(1ll*(n-i)*(n-i+1)/2);
}printf("%d\n",(ans+mod)%mod);
return 0;
}
AGC044E Random Pawn
题意:有一个环,初始等概率出生在一个整点,每个时刻在位置 \(p\) 可以选择停止并获得 \(a_p\),或者继续,交付 \(b_p\) 并随机移动到 \(p-1\) 或 \(p+1\)。求期望收益。
瞎扯:需要满足 \(E_x=\max\{a_x,-b_x+\frac{E_{x-1}+E_{x+1}}2\}\),并且已知 \(a_x\) 最大时 \(E_x=a_x\)。你看这个一脸凸包的样子,然而我不会处理。
正解:我们考虑从 \(a\) 最大处断环为链。有一个 trick 就是说:
对于形如 \(f_i=\max\{a_i,\frac{f_{i-1}+f_{i+1}}{2}\}\) 的转移,我们将 \((i,a_i)\) 做一个凸包,然后把所有不在边上的点挪到边上即可。
我们考虑将方程变换为上述形式。随意变换即可。
#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
#define db double
int n,m;db a[maxn<<1],b[maxn<<1],c[maxn<<1];
int q[maxn],top;db ans;
inline db slope(int x,int y){return (a[y]-a[x])/(y-x);}
int main(){
n=read();db Mx=-1;int p=0;
for(int i=1;i<=n;i++)scanf("%lf",a+i),a[n+i]=a[i];
for(int i=1;i<=n;i++)scanf("%lf",b+i),b[n+i]=b[i];
for(int i=1;i<=n;i++)if(a[i]>Mx)Mx=a[i],p=i;q[++top]=p;
if(n==2)return printf("%.12lf\n",(Mx+max(a[p+1],Mx-b[p+1]))/2)&0;
for(int i=p+2;i<=n+p;i++)c[i]=2*(b[i-1]+c[i-1])-c[i-2],a[i]-=c[i];
for(int i=p+1;i<=n+p;i++){
while(top>1&&slope(q[top-1],q[top])<slope(q[top],i))top--;
q[++top]=i;
}
for(int i=1;i<top;i++){
db k=slope(q[i],q[i+1]);
db b=a[q[i]]-k*q[i];
for(int j=q[i];j<q[i+1];j++)ans+=k*j+b+c[j];
}printf("%.12lf\n",ans/n);
return 0;
}