T1
一度以为考场上写不完…虽然最终杠完了
考虑两个位置
i
,
j
i,j
i,j上的数做完
k
k
k次操作后顺序是否变换的方案数
那么就是
d
p
[
i
]
[
j
]
[
k
]
[
0
/
1
]
dp[i][j][k][0/1]
dp[i][j][k][0/1]了
对于
n
3
k
n^3k
n3k的转移,枚举一下中间点是什么然后讨论
对于
n
2
k
n^2k
n2k的转移,我们分几种情况讨论
分别是区间覆盖了
[
i
,
j
]
[i,j]
[i,j]两个数,只覆盖了
i
i
i,只覆盖了
j
j
j,与什么都不覆盖的
我们注意到
[
i
,
j
]
[i,j]
[i,j]想要变为
[
x
,
y
]
[x,y]
[x,y],翻转区间的中心是确定的
只需要知道两边边界最多有多少
那么讨论边界转移即可…
有时间把代码扔上来吧…说可能说不清
upd:来噜
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;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();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=501;
const int MAXK=51;
const int mod=1e9+7;
void ad(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int a[MAXN],n,K;
int f[2][MAXN][MAXN][2];//0 不换位 1 换位
int f1[MAXN][MAXN][2],f2[MAXN][MAXN][2];
int g1[MAXN][MAXN][2],g2[MAXN][MAXN][2];
int u1[MAXN][MAXN][2],u2[MAXN][MAXN][2];
int v1[MAXN][MAXN][2],v2[MAXN][MAXN][2];
//1 表示乘了i,2表示没乘i
inline int add(int x,int y){return (x+y>=mod)?(x+y-mod):(x+y);}
inline void prenext(int nw)
{
// memset(f1,0,sizeof(f1));memset(f2,0,sizeof(f2));
// memset(g1,0,sizeof(f1));memset(g2,0,sizeof(f2));
// memset(u1,0,sizeof(f1));memset(u2,0,sizeof(f2));
// memset(v1,0,sizeof(f1));memset(v2,0,sizeof(f2));
for(register int i=n;i>=1;--i)for(register int j=i+1;j<=n;++j)for(register int k=0;k<=1;++k)
{
int len=j-i;
g1[i][len][k]=add(g1[i+1][len][k],1LL*f[nw][i][j][k]*i%mod);
g2[i][len][k]=add(g2[i+1][len][k],f[nw][i][j][k]);
}
for(register int i=1;i<=n;++i)for(register int j=1;j<i;++j)for(register int k=0;k<=1;++k)
{
int len=i-j;
f1[i][len][k]=add(f1[i-1][len][k],1LL*f[nw][j][i][k]*(n-i+1)%mod);
f2[i][len][k]=add(f2[i-1][len][k],f[nw][j][i][k]);
}
for(register int i=1;i<=n;++i)for(register int j=i-1;j>=1;--j)for(register int k=0;k<=1;++k)
{
int len=i-j;
u1[i][j][k]=add(u1[i][j+1][k],1LL*f[nw][j][i][k]*j%mod);
u2[i][j][k]=add(u2[i][j+1][k],f[nw][j][i][k]);
}
for(register int i=1;i<=n;++i)for(register int j=n;j>i;--j)for(register int k=0;k<=1;++k)
{
int len=j-i;
v1[i][j][k]=add(v1[i][j+1][k],1LL*f[nw][i][j][k]*j%mod);
v2[i][j][k]=add(v2[i][j+1][k],f[nw][i][j][k]);
}
}
inline int calc(int u)
{
if(u<1)return 0;
return 1LL*u*(u+1)/2%mod;
}
int pow_mod(int a,int b)
{
int ret=1;
while(b)
{
if(b&1)ret=1LL*ret*a%mod;
a=1LL*a*a%mod;b>>=1;
}
return ret;
}
int main()
{
freopen("inverse.in","r",stdin);
freopen("inverse.out","w",stdout);
n=read();K=read();
for(register int i=1;i<=n;i++)a[i]=read();
for(register int i=1;i<=n;++i)for(register int j=1;j<=n;++j)f[0][i][j][0]=1;
prenext(0);int nw=0;
for(register int T=1;T<=K;++T)
{
nw^=1;memset(f[nw],0,sizeof(f[nw]));
for(register int i=1;i<=n;++i)for(register int j=i+1;j<=n;++j)for(register int k=0;k<=1;++k)
{
int len=j-i;
//先弄区间在左边的
int lim=n-j+1;
if(lim<=i)ad(f[nw][i][j][k],1LL*(g2[lim][len][k^1]-g2[i+1][len][k^1]+mod)%mod*lim%mod);
ad(f[nw][i][j][k],(g1[1][len][k^1]-g1[min(lim,i+1)][len][k^1]+mod)%mod);
//再弄区间在右边的
lim=i;
if(n-lim+1>j)ad(f[nw][i][j][k],1LL*(f2[n-lim+1][len][k^1]-f2[j][len][k^1]+mod)%mod*lim%mod);
ad(f[nw][i][j][k],(f1[n][len][k^1]-f1[max(n-lim+1,j)][len][k^1]+mod)%mod);
//弄只变了左边位置的
//在i左边(包括i
lim=j-i;
if(lim<=i)ad(f[nw][i][j][k],1LL*(u2[j][lim][k]-u2[j][i+1][k]+mod)%mod*lim%mod);
ad(f[nw][i][j][k],(u1[j][1][k]-u1[j][min(lim,i+1)][k]+mod)%mod);
//在i右边
int o=j-1;
lim=i;
if(o-lim+1>i)ad(f[nw][i][j][k],1LL*(u2[j][i+1][k]-u2[j][o-lim+2][k]+mod)%mod*lim%mod);
ad(f[nw][i][j][k],(1LL*u2[j][max(o-lim+2,i+1)][k]*(o+1)%mod-u1[j][max(o-lim+2,i+1)][k]+mod)%mod);
//在j右边(包括j
lim=j-i;
if(n-lim+1>=j)ad(f[nw][i][j][k],1LL*(v2[i][j][k]-v2[i][n-lim+2][k]+mod)%mod*lim%mod);
ad(f[nw][i][j][k],(1LL*v2[i][max(n-lim+2,j)][k]*(n+1)%mod-v1[i][max(n-lim+2,j)][k]+mod)%mod);
o=i+1;lim=n-j+1;
if(o+lim-1<j)ad(f[nw][i][j][k],1LL*(v2[i][o+lim-1][k]-v2[i][j][k]+mod)%mod*lim%mod);
ad(f[nw][i][j][k],((v1[i][i+1][k]-v1[i][min(o+lim-1,j)][k]+mod)%mod-1LL*(v2[i][i+1][k]-v2[i][min(o+lim-1,j)][k]+mod)%mod*(o-1)%mod+mod)%mod);
ad(f[nw][i][j][k],1LL*f[nw^1][i][j][k]*(calc(i-1)+calc(j-i-1)+calc(n-j))%mod);
}
prenext(nw);
}
int ans=0;
for(register int i=1;i<=n;++i)for(register int j=i+1;j<=n;++j)
{
if(a[i]<a[j])ad(ans,f[nw][i][j][1]);
else ad(ans,f[nw][i][j][0]);
}
LL inv=pow_mod(1LL*n*(n+1)/2%mod,mod-2);
inv=pow_mod(inv,K);
pr2(1LL*ans*inv%mod);
return 0;
}
**T2
打表题不会做…
朴素
f
(
i
,
j
)
f(i,j)
f(i,j)表示前
i
i
i个数长度为
j
j
j的子序列最大值
转移就是
f
(
i
,
j
)
=
m
a
x
(
f
(
i
−
1
,
j
)
,
f
(
i
−
1
,
j
−
1
)
+
a
[
i
]
∗
j
)
f(i,j)=max(f(i-1,j),f(i-1,j-1)+a[i]*j)
f(i,j)=max(f(i−1,j),f(i−1,j−1)+a[i]∗j)
打表发现对于每个
i
i
i,取第二种转移的是连续一段后缀
那么splay维护dp值的差分
一次只需要插入一个
a
[
i
]
∗
k
a[i]*k
a[i]∗k并且给后面的全部打上加
a
[
i
]
a[i]
a[i]的标记
T3
误认为面积不能推下去所以…自闭了
一个显然的想法就是我们按逆时针扫点,这样可以去掉叉积的绝对值
我们还需要去掉面积差的绝对值,那就强行让选中的一片区域是较小的那个
那么一个点能选择编号最远的那个点是单调的
我们可以维护一段区间内的多边形面积和
容易发现,对于以
k
k
k号点为序号最大点的多边形,他少了的面积是三角形
p
i
,
p
i
+
1
,
p
k
p_i,p_{i+1},p_k
pi,pi+1,pk的面积
推一下叉积,以下坐标以下标作为编号
(
x
i
+
1
−
x
i
)
(
y
k
−
y
i
)
−
(
x
k
−
x
i
)
∗
(
y
i
+
1
−
y
i
)
(x_{i+1}-x_i)(y_k-y_i)-(x_k-x_i)*(y_{i+1}-y_i)
(xi+1−xi)(yk−yi)−(xk−xi)∗(yi+1−yi)
x
i
+
1
y
k
−
x
i
+
1
y
i
−
x
i
y
k
+
x
i
y
i
−
x
k
y
i
+
1
+
x
k
y
i
−
x
i
y
i
+
x
i
y
i
+
1
x_{i+1}y_k-x_{i+1}y_i-x_iy_k+x_iy_i-x_ky_{i+1}+x_ky_i-x_iy_i+x_iy_{i+1}
xi+1yk−xi+1yi−xiyk+xiyi−xkyi+1+xkyi−xiyi+xiyi+1
y
i
(
x
k
−
x
i
+
1
)
+
y
i
+
1
(
x
i
−
x
k
)
+
y
k
(
x
i
+
1
−
x
i
)
y_i(x_k-x_{i+1})+y_{i+1}(x_i-x_k)+y_k(x_{i+1}-x_i)
yi(xk−xi+1)+yi+1(xi−xk)+yk(xi+1−xi)
可以前缀和优化了