1. 程式人生 > 實用技巧 >「USACO06NOV」玉米田 Corn Fields

「USACO06NOV」玉米田 Corn Fields

基礎知識:

  

tips: 版本1用來求符合條件的值中下標最小的那個,版本2求符合條件中的下標最大的那個。

1. 最佳牛圍欄

  題目連結:https://www.acwing.com/problem/content/104/(演算法競賽進階指南)

   思路:1. 二分的方法來列舉所有可能的平均值

      2. 檢驗當前的平均值是否符合條件, 如果符合條件就調大平均值,如果不符合條件就減小平均值

      3. 檢驗方法:求當前陣列的字首和並將每一項都減去平均值。記錄所有大於等於m長度的區間的值,

       如果有區間的值大於1,說明對於該區間,當前平均值偏小,即符合條件。

   程式碼:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 100010;

int n, m;
int cows[N];
double sum[N];

bool check(double avg)
{
    for(int i = 1; i <= n; i++) 
        sum[i] = sum[i - 1] + cows[i] - avg;
        
    double minv = 0;
    for(int i = 0, j = m; j <= n; j++, i++)
    {
        
//儲存所有區間的最小值,因為j是從m開始列舉, //因此字首區間sum[j] - sum[i]的長度一定大於m minv = min(minv, sum[i]); if(sum[j] >= minv) return true; } return false; } int main() { cin >> n >> m; for(int i = 1; i <= n; i++) cin >> cows[i]; double left = 0
, right = 2000; while(right - left > 1e-5) { double mid = (left + right) / 2; if(check(mid)) left = mid; else right = mid; } printf("%d\n", int(right * 1000)); return 0; }

2.特殊排序

  題目連結:https://www.acwing.com/problem/content/115/(演算法競賽進階指南)

   思路:

    方法1:每次取出一個數字,通過二分的方法找到這個數字在當前陣列中的位置,將當前元素新增到vector最後,通過插入排序將當前元素放到正確的位置

    程式碼1:

class Solution {
public:
    vector<int> specialSort(int N) {
        vector<int> res;
        res.push_back(1);
        for(int i = 2; i <= N; i++)
        {
            int left = 0; int right = res.size() - 1;
            while(left < right)
            {
                int mid = left + right + 1 >> 1;
                if(compare(res[mid], i)) left = mid;
                else right = mid - 1;
            }
            
            res.push_back(i);
            for(int j = res.size() - 2; j > right; j--)
            {
                swap(res[j], res[j + 1]);
            }
            
            //排除邊界條件,如果所有的數字都大於當前的數字,需要特殊判斷
            if(compare(i, res[right])) swap(res[right], res[right + 1]);
        }
        
        return res;
    }
};

     方法2:歸併排序

    程式碼2:

class Solution {
public:
    vector<int> merge(int l,int r,int N)//merge函式返回l到r區間已經排好序的vector容器
    {
        if (l == r)//遞迴出口,如果只有一個元素,直接把這個元素返回即可
        {
            vector<int>temp;
            temp.push_back(l);
            return temp;
        }
        int mid = (l + r) / 2;
        vector<int>a=merge(l,mid,N);//遞迴求解
        vector<int>b=merge(mid+1,r,N);
        vector<int>res;//res是一會要返回的容器
        int t1=0,t2=0;//t1和t2分別指向a和b容器中的元素
        int flag=0;
        while(t1<a.size()&&t2<b.size())
        {
            if(compare(a[t1],b[t2]))//如果a中元素小,就把a中元素壓入res中
            {
                res.push_back(a[t1++]);
            }
            else
            {
                res.push_back(b[t2++]);
            }
            if(t1>=a.size())//如果t1已經指向了a容器末尾,flag=1表示a已經遍歷完全
            {
              flag=1;break;  
            }
            if(t2>=b.size())//同理
            {
                flag=2;break;
            }
        }
        if(flag==1)//把b中剩餘元素壓入res中
        {
            for(int i=t2;i<b.size();i++)
            {
                res.push_back(b[i]);
            }
        }
        else//同理
        {
            for(int i=t1;i<a.size();i++)
            {
                res.push_back(a[i]);
            }
        }
        return res;
    }
    vector<int> specialSort(int N) {
        vector<int>ans=merge(1,N,N);
        return ans;
    }
};