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