Luogu6967 [NEERC2016]Delight for a Cat
Luogu6967 [NEERC2016]Delight for a Cat
单纯形法
太弱了,不会网络流,只好用单纯形法辗过去。
很容易发现,这是一个线性规划问题,我们可以设\(n\)个变量\(x_1,x_2,\cdots,x_n\)表示每个时刻猫的状态,\(x_i=0\)表示猫在\(i\)时刻进食,\(x_i=1\)表示猫在\(i\)时刻睡觉。
我们可以列出以下这些方程:
\[\begin{cases}
0 \le x_1 \le 1 \\
0 \le x_2 \le 1 \\
\cdots\\
0 \le x_n \le 1 \\
\sum_{i=1}^k x_i \ge ms \\
k-\sum_{i=1}^k x_i \ge me\\
\cdots\\
\sum_{i=n-k+1}^n x_i \ge ms \\
k-\sum_{i=n-k+1}^n x_i \ge me\\
\end{cases}
\]
求:
\[\max \sum_{i=1}^n s_i x_i + e_i (1-x_i)
\]
根据线性规划整数最优解的判定条件,可以证明整数解一定是本题中线性规划的最优解(伪证:因为本题可以费用流,所以单纯形法能够跑出整数解)。
把方程经过添加负号等变换,转化为标准形式,然后直接跑单纯形法。
提交一下,发现\(TLE\)了。
实际上,我们这里的单纯形法需要初始化,因为一开始的全\(0\)解是不合法的,这会消耗大量时间,引用一句话:
需要注意的一点是,大部分的OI试题得出的限制条件都有一定的性质,而执行初始化操作会破坏这些性质,造成运行时间的无谓增加。 ——董克凡《浅谈线性规划与对偶问题》
因此我们可以考虑手动初始化,也就是找到一组合法解,实际上这很容易构造,我们让\(me\)个\(E\),\(k-me\)个\(S\)不断循环得到一个长度为\(n\)的序列,容易发现,任意一个长度为\(k\)的子区间都含有\(me\)个\(E\),\(k-me\)个\(S\),显然合法。
我们把这个序列作为标准序列,把\(x_i\)重新定义,即\(x_i=0\)表示\(i\)时刻状态与标准序列中\(i\)时刻状态不同,\(x_i=1\)表示\(i\)时刻状态与标准序列中\(i\)时刻状态相同。
然后再跑单纯形法就可以通过本题了。
\(Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define db double
using namespace std;
const db eps=1e-7;
int n,m,k,ms,me,s[1005],e[1005],id[4005];
db z,ans[4005],a[3005][1005];
bool r[1005];
void pivot(int l,int e)
{
swap(id[n+l],id[e]);
db t(a[l][e]);
a[l][e]=1.0;
for (int i=0;i<=n;++i)
a[l][i]/=t;
for (int i=0;i<=m;++i)
if (i!=l && fabs(a[i][e])>eps)
{
db t(a[i][e]);
a[i][e]=0.0;
for (int j=0;j<=n;++j)
a[i][j]-=t*a[l][j];
}
}
void simplex()
{
for (;;)
{
int e(0),l(0);
db mx(eps);
for (int i=1;i<=n;++i)
if (a[0][i]>mx)
mx=a[0][i],e=i;
if (!e)
return;
db mn(1e18);
for (int i=1;i<=m;++i)
if (a[i][e]>eps && a[i][0]/a[i][e]<mn)
mn=a[i][0]/a[i][e],l=i;
pivot(l,e);
}
}
int main()
{
scanf("%d%d%d%d",&n,&k,&ms,&me);
for (int i=1;i<=n;++i)
scanf("%d",&s[i]);
for (int i=1;i<=n;++i)
scanf("%d",&e[i]);
for (int i=1;i<=n;++i)
{
r[i]=((i-1)%k+1>me);
if (r[i])
z+=s[i],a[0][i]=e[i]-s[i]; else
z+=e[i],a[0][i]=s[i]-e[i];
a[i][0]=1.0,a[i][i]=1.0;
}
m=n;
for (int i=1;i<=n-k+1;++i)
{
++m,a[m][0]=-ms;
for (int j=i;j<i+k;++j)
a[m][j]=-1.0;
++m,a[m][0]=k-me;
for (int j=i;j<i+k;++j)
a[m][j]=1.0;
}
for (int i=1;i<=n;++i)
if (r[i])
for (int j=n+1;j<=m;++j)
a[j][0]-=a[j][i],a[j][i]=-a[j][i];
for (int i=1;i<=n;++i)
id[i]=i;
simplex();
for (int i=1;i<=m;++i)
ans[id[n+i]]=a[i][0];
printf("%.lf\n",z-a[0][0]);
for (int i=1;i<=n;++i)
putchar(((fabs(ans[i])>eps) ^ r[i])?'S':'E');
putchar('\n');
return 0;
}