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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值