2017 暑假艾教集訓 day1

1.蓄水池問題

http://acm.nyist.net/JudgeOnline/problem.php?pid=547

做法:先把池子的四周用優先隊列存起來,枚舉每個點向四個方向延伸(注意vis數組),如果拓展點的高度小於當前節點的高度 ans+=(H[now]-H[ex]) 並且把拓展點的高度改爲當前點的高度  否則直接扔進隊列即可,


a.UvaLive 7147

做法:做過第二遍了,只用將最特殊的人拿出來討論一下即可。


b.Uvalive 7146

做法:做過第二遍了,對自己的軍隊攻擊排序,對敵人的防禦排序(均從大到小)。 遍歷敵人軍隊,當攻擊力大於當前敵人軍隊的防禦 時,將自己軍隊的防禦加入  多重set中。 用upper_bound 找出比敵人軍隊攻擊略大的攻擊,然後刪去,如果不存在直接刪去 多重set第一個節點,並記錄 死人++;


POJ 1222

做法:每次枚舉第一列是否開關燈,如果第一列定了那麼最後一列也就一定定了。只用再判斷最後一列是否全部都關燈即可


CF 729D

做法:貪心,如果能放船就直接放,當放過n-1個船後,剩下還能放的船個數,和所佔空間的任意點 就是答案,


CF 500C

做法:模擬+亂搞.

容易得到一個定理(如果這個數是第一次出現,且爲第I個, 那麼它就是初始的第I個 )

比如 (1 1 1  3  3 2 2 ) -》 (1 3 2)

然後模擬一哈  主要就是這兩個操作就行了
                now.erase(now.begin()+j); 拿出
                now.insert(now.begin(),q[i]); 放回


CF 550C

做法:剛開始就暴力DFS+胡亂剪枝,結果TLE。 後來發現只用枚舉三位數即可,因爲1000/8=125; 所以四位以上沒必要,O(n3)暴力枚舉即可


CF 672D

做法:兩次二分, 依次二分 最小鋼板數量,和最大鋼板數量 ,兩個一減就是答案。

判斷的時候有個定理:硬幣改變的值和爲改變天數(當找小值時候只用考慮 初始比二分mid 還要小的就可以了,找最大同理)


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,k;
int a[600000];
bool mincheck(int mid)
{
    ll sum=0;
    for(int i=1;i<=n;++i)
    {
        if(a[i]<mid) sum+=(ll)(mid-a[i]);
    }
    return sum<=k;
}

bool maxcheck(int mid)
{
    ll sum=0;
    for(int i=1;i<=n;++i)
    {
        if(a[i]>mid) sum+=(ll)(a[i]-mid);
    }
    return sum<=k;
}

int main()
{
    ll sum=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)  { scanf("%d",&a[i]); sum+=(ll) a[i];}

    int maxdown,minup;
    if(sum%n==0)
    {
        maxdown = minup =(sum/n);
    }
    else
    {
        maxdown = (sum/n);
        minup =maxdown+1;
    }

    int l=0,r=maxdown;
    int minm=0,maxm=0;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(mincheck(mid)) { l=mid+1; minm=mid; }
        else r=mid-1;
    }
    l=minup ; r=1e9;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(maxcheck(mid)) {r=mid-1; maxm=mid;}
        else l=mid+1;
    }
    printf("%d\n",maxm-minm);
    return 0;
}

CF 485 D

做法:只會暴力死活T。 結果看了別人的亂搞。

逆其道而行之,枚舉公倍數前一個數即可。(具體看代碼把,還是很難理解的)

#include <bits/stdc++.h>
using namespace std;
int vis[2000050*2];
int main()
{
    memset(vis,-1,sizeof(vis));
    int n;
    scanf("%d",&n);
    vis[1]=1;
    for(int i=1;i<=n;++i)
    {
        int x;
        scanf("%d",&x);
        vis[x]=x;
    }
    for(int i=1;i<=2000050;++i)
    {
        if(vis[i]==-1) vis[i]=vis[i-1];
    }

    int ans=0;

    for(int i=1;i<=1000050;++i)
    {
        if(vis[i]==i)
        {
            for(int j=2*i;j<=2000050;j+=i)
            {
                if(vis[j-1]>i) ans=max(ans,vis[j-1]%i);
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章