2017 暑假艾教集训 day1

来源:互联网 发布:黑手党 知乎 编辑:程序博客网 时间:2024/05/17 08:37

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;}