您的位置:首页 > 其它

Codeforces Beta Round #61 (Div. 2) E. Petya and Post

2014-09-01 15:53 330 查看
考虑最暴力的方法 ,就是从每点去模拟,用一个变量cur记录当前油箱的油量,一旦发现某个时刻cur小于0,则是无解。但这个做法一定是不可以了,会超时。

不过我们可以从暴力做法里面获得一些启发。考虑cur在变化过程中的最小值min_cur,明显有min_cur<=0,记dp[i]为从i点出发,想要转一圈回来,在i点未加油时最少需要的油量是多少。显然dp[i]=min_cur.

题目还有一个重要的信息,对a求和等于对b求和。那么在暴力求法中,cur最后一定归0(中途可能是负的),那么也就是说,在终点前一个点加油后油量一定是正的。那么dp[i]就有另一个含义从i点出发沿i,i+1,i+2,...,走到i-1所需的最小油量,因为能走到i-1,就一定能到i。

那么

dp[i]=max(b[i]-a[i],dp[i+1]-(a[i]-b[i]))=max(b[i]-a[i],dp[i+1]-a[i]+b[i])=dp[i+1]-a[i]+b[i] (dp[i+1]>=0)

b[i]-a[i]表示能从i到i+1

dp[i+1]-a[i]+b[i]表示先从i到i+1,在从i+1到i(dp[i+1]取第二个含义),合起来就是从i到i(dp[i]取第一个含义)

这样从任意一个点暴力求一次dp[i],再O(n)递推其他点的dp值即可。注意题目中有两个方向,那么做两次即可。

#include <bits/stdc++.h>
#define maxn 100009
using namespace std;
bool vis[maxn];
int a[maxn],b[maxn],dp[maxn],n;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&b[i]);
int cur=0;
for(int i=0;i<n;i++)
{
cur=cur+a[i]-b[i];
dp[0]=min(dp[0],cur);
}
dp[0]=-dp[0];
if(dp[0]==0)
vis[0]=1;
for(int i=n-1;i>0;i--)
{
dp[i]=dp[(i+1)%n]-(a[i]-b[i]);
if(dp[i]==0)
vis[i]=1;
}
memset(dp,0,sizeof(dp));
cur=0;
for(int i=n-1;i>=0;i--)
{
cur=cur+a[i]-b[((i-1)%n+n)%n];
dp[n-1]=min(dp[n-1],cur);
}
dp[n-1]=-dp[n-1];
if(dp[n-1]==0)
vis[n-1]=1;
for(int i=0;i<n-1;i++)
{
dp[i]=dp[((i-1)%n+n)%n]-(a[i]-b[((i-1)%n+n)%n]);
if(dp[i]==0)
vis[i]=1;
}
int cnt=0;
for(int i=0;i<n;i++)
{
if(vis[i])
cnt++;
}
printf("%d\n",cnt);
for(int i=0;i<n;i++)
{
if(vis[i])
printf("%d ",i+1);
}
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: