zoukankan      html  css  js  c++  java
  • 【环形线性区间dp】【CF】E. Petya and Post

    【环形线性区间dp】[CF]E. Petya and Post

    image

    题意(稍微变型):有n个加油站,编号为1到n,且每个加油站都能提供(a_i)的油量(只能提供一次),并且从一个加油站到相邻的加油站会消耗一定量的油量。求在这n个加油站中有几个加油站可以满足顺时针或者逆时针地整整跑完一圈?

    思路:如果中途一旦出现油量小于0的情况(假设真的能)就说明车子停到一半,就没有继续跑了。

    dp[i]表示从i点出发且最终又回到终点这样的路线中间出现了的最小值(这是一个非常重要且起决定作用的因素)

    先单单从顺时针方向进行考虑,从点i+1出发和从点i出现的不同之处在于从i+1点出发的所有过程脱去先从i点取到油并且耗费一定油最终剩余或者亏欠的油量的影响,而,而脱去某种影响意思就是要去做一下修正操作,而这个修正操作也会直接影响到中途出现的最小值(最危险的情况),如果是

    (D_1=a_1-b_1), (第i个点出发到i+1点的且没在i+1点加油的情况)

    (D_2=(a_1+a_2)-(b_1+b_2)), (第i个点出发到i+2点的且没在i+2点加油的情况)

    (D_3=(a_1+a_2+a_3)-(b_1+b_2+b_3)),

    (Dn=(a_1+a_2+…+a_n)-(b_1+b_2+…+b_n))

    (D_{min}=min{D_i})

    (E_1=a_2-b_2=D_2-(a_1-b_1)),

    (E_2=(a_2+a_3)-(b_2+b_3)=D_3-(a_1-b_1)),

    (E_3=(a_2+a_3+a_4)-(b_2+b_3+b_4)=D_4-(a_1-b_1)),

    (E_{n-1}=(a_2+…+a_n)-(b_2+…+b_n)=D_n-(a_1-b_1))

    (En=(a_2+…+a_n+a_1)-(b_2+…+b_n+b_1))

    可以建立坐标系,将E和D的函数绘制出来,发现E的图像基本上是D的图像左移一个单位并向下平移((a_1-b_1))绘制出来,也就是说最小值的位置是没有发生变化的

    (E_{min}=min{E_i}=D_{min}-(a_1-b_1))

    (F_1=E_2-(a_2-b_2))

    ...

    (F_{n-1}=(a_3+…+a_n+a_1)-(b_3+…+b_n+b_1)=E_n-(a_2-b_2))

    同理,可以建立坐标系,将E和D的函数绘制出来,发现E的图像基本上是D的图像左移一个单位并向下平移((a_2-b_2))绘制出来,也就是说最小值的位置是没有发生变化的

    #include <bits/stdc++.h>
    #define MEM(a,x) memset(a,x,sizeof(a))
    #define W(a) while(a)
    #define gcd(a,b) __gcd(a,b)
    #define pi acos(-1.0)
    #define PII pair<int,int>
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define ll long long
    #define ull unsigned long long
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define MAX 1000005
    #define MOD 1000000007
    #define INF 0x3f3f3f3f
    #define lowbit(x) (x&-x)
    using namespace std;
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
    inline int read()
    {
        int 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();
        return x*f;
    }
    const int N = 1E5+5;
    int n,m,dp[N];
    bool ans[N];
    int main()
    {
    	n=read();
    	int A[n+1],B[n+1];
    	for(int i=1;i<=n;i++)
            A[i] = read();
        for(int i=1;i<=n;i++)
            B[i] = read();
        int tmp=0;
        for(int i=1;i<=n;i++)
        {
        	tmp+=A[i]-B[i];
            dp[1]=min(dp[1],tmp);
    	}
    	if(dp[1]>=0) ans[1]=1;
    	for(int i=2;i<=n;i++)
    	{
    		dp[i]=dp[i-1]-(A[i-1]-B[i-1]);
    	    if(dp[i]>=0) ans[i]=1;
    	}    
    	//逆时针相当于把第n个点倒一下当成起点 
    	tmp=0,B[0]=B[n];
    	memset(dp,0,sizeof(dp));
        for(int i=n;i>=1;i--)
        {
        	tmp+=A[i]-B[i-1];
            dp[n]=min(dp[n],tmp);
    	}
    	if(dp[n]>=0) ans[n]=1;
    	for(int i=n-1;i>=1;i--)
    	{
    		dp[i]=dp[i+1]-(A[i+1]-B[i]);
    	    if(dp[i]>=0) ans[i]=1;
    	} 
    	vector<int> vec;   
    	for(int i=1;i<=n;i++)
    	    if(ans[i]) vec.push_back(i);
        sort(vec.begin(),vec.end());
        cout<<vec.size()<<endl;
        for(int i=0;i<vec.size();i++)
        {
        	if(i!=0) cout<<" ";
            cout<<vec[i];
    	}
        return 0;
    }
    
    
  • 相关阅读:
    stringstream用法
    C# WinForm设置窗口无边框、窗口可移动、窗口显示在屏幕中央、控件去边框
    C# WinForm设置窗口大小不可调,取消最大、最小化按键
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal 由前序和中序遍历建立二叉树 C++
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal 由中序和后序遍历建立二叉树 C++
    LeetCode 112. Path Sum 二叉树的路径和 C++
    LeetCode 101. Symmetric Tree 判断对称树 C++
    LeetCode 100. Same Tree 判断两棵二叉树是否相等 C++
    C# winform三种方法判断文本框textBox内容是否为空
    LeetCode 145. Binary Tree Postorder Traversal 二叉树的后序遍历 C++
  • 原文地址:https://www.cnblogs.com/BeautifulWater/p/15422171.html
Copyright © 2011-2022 走看看