2017 暑假艾教集训 day1

时间:2021-07-03 16:43:13

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