【CodeForces - 608C】Chain Reaction (二分 或 dp ,思维)
題干:
?
題目大意:
題意是在一條直線上坐落著不同位置的燈塔,每一個燈塔有自己的power level,當作是射程范圍。現在從最右邊的燈塔開始激發,如果左邊的燈塔在這個燈塔的范圍之內,那么將會被毀滅。否則會被激發,留下自己。
解題報告:
dp求解:
現在可以從右邊放置一個燈塔,位置和power level都可以自己定義。問各種情況中最小的燈塔被毀滅的數量。
dp[x]表示到x個燈塔的時候毀滅的最小數量。對于第x個燈塔來說,求出不再自己范圍內的上一個的燈塔位置i,因此在自己范圍內的燈塔數量也能夠得知x-i+1。
那么會有dp[x]=dp[i]+x-i+1。這個是在第x炸彈被激發的情況下,毀滅的燈塔數量。
而今,因為可以在右邊放置一個燈塔了。所以就求出dp[i]+(n-i) (1<=i<=n)的最小值。
AC代碼1:(標解dp)
?
AC代碼2:(二分)
#include<bits/stdc++.h>using namespace std; pair<int,int> pr[100000 + 5]; int dp[100000 + 5]; int main() {int n;cin>>n;for(int i = 1; i<=n; i++) {scanf("%d%d",&pr[i].first,&pr[i].second);}sort(pr+1,pr+n+1);dp[0]=0; // pr[n+1].first=-1;for(int i = 1; i<=n; i++) {int loc = lower_bound(pr+1,pr+i+1,make_pair(pr[i].first - pr[i].second,-1)) - pr;if(loc)dp[i] = dp[loc - 1] + (i-loc);else dp[i] = i-1; // printf("%d = %d\n",i,dp[i]);}int minn = 0x3f3f3f3f;for(int i = 1; i<=n; i++) {minn = min(minn,dp[i] + (n-i) );}printf("%d\n",minn);return 0 ; }AC代碼3:(網絡版的二分,跟第二個差不多)
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define INF 0x3fffffffconst int maxn = 100005;int n; int dp[maxn];//記錄毀滅的最小值 struct no {int a;int b; } node[maxn]; bool cmp(const no &n1, const no &n2) {return n1.a < n2.a; } void solve() {int i;sort(node + 1, node + n + 1, cmp);for (i = 1; i <= n; i++) {no nx;nx.a = node[i].a - node[i].b;int pos = lower_bound(node + 1, node + n + 1, nx, cmp) - node;if (pos)dp[i] = dp[pos - 1] + (i - pos);//因為最靠右的會被激發,致使范圍之內的會被毀滅elsedp[i] = i - 1;//除了自己全部毀滅 // printf("%d = %d\n",i,dp[i]);}int res = n;for (i = 1; i <= n; i++) {res = min(res, dp[i] + (n - i));}printf("%d", res); }int main() {scanf("%d",&n);for (int i = 1; i <= n; i++) {scanf("%d%d", &node[i].a, &node[i].b);}solve();return 0; }依舊二分AC4:
#include<bits/stdc++.h>using namespace std; const int MAX = 1e5 + 5; int dp[MAX]; pair<int,int> pr[MAX]; int main() {int n;cin>>n;for(int i = 1; i<=n; i++) {scanf("%d%d",&pr[i].first,&pr[i].second);}sort(pr+1,pr+n+1);dp[1]=1;//記錄存活個數 // dp[0]=0;for(int i = 2; i<=n; i++) {if(pr[i].first - pr[i].second <=0) {dp[i]=1;continue;}int pos = lower_bound(pr+1,pr+i+1,make_pair(pr[i].first - pr[i].second,-1)) - pr;//會被輻射到的 pos--;//第一個不會被輻射到的dp[i] = dp[pos]+1;}int minn = 0x3f3f3f3f;for(int i = 1; i<=n; i++) {//minn = min(minn,n - i + (i-dp[i]));minn = min(minn,n-dp[i]);}printf("%d\n",minn);return 0 ;}依舊二分AC5:
#include<bits/stdc++.h>using namespace std; const int MAX = 1e5 + 5; int dp[MAX]; pair<int,int> pr[MAX]; int main() {int n;cin>>n;for(int i = 1; i<=n; i++) {scanf("%d%d",&pr[i].first,&pr[i].second);}sort(pr+1,pr+n+1); // dp[1]=1;//記錄存活個數 dp[0]=0;for(int i = 1; i<=n; i++) {//這里是從1開始了、、、 // if(pr[i].first - pr[i].second <=0) {dp[i]=1;continue;}int pos = lower_bound(pr+1,pr+i+1,make_pair(pr[i].first - pr[i].second,-1)) - pr;//會被輻射到的 pos--;//第一個不會被輻射到的dp[i] = dp[pos]+1;}int minn = 0x3f3f3f3f;for(int i = 1; i<=n; i++) {//minn = min(minn,n - i + (i-dp[i]));minn = min(minn,n-dp[i]);}printf("%d\n",minn);return 0 ;}ps:其實上面幾個代碼都可以lowerbound(pr+1 , pr+i , ....) - pr 就行了,不需要pr+i+1.。。但是其實好像是一模一樣的。(本以為可以不用判斷pos的結果等于pre的情況(也就是一個都沒找到? ?的情況),但是發現這樣寫也是要考慮的,因為你pr+i的話,lowerbound沒找到也是要返回pos==pre這個的啊,結合那個【CodeForces - 799C】Fountains去理解下、、)
二分網絡版AC代碼6:(其實跟AC代碼4是一樣的)
//meek///#include<bits/stdc++.h> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include<iostream> #include<bitset> using namespace std ; #define mem(a) memset(a,0,sizeof(a)) #define pb push_back #define fi first #define se second #define MP make_pair typedef long long ll;const int N = 201000; const int M = 1000001; const int inf = 0x3f3f3f3f; const int MOD = 100003; const double eps = 0.000001;struct ss{int p,s,S; }a[N]; int n,b[N],H[N],t[M],sum[N],dp[M+5]; int cmp(ss s1,ss s2) {return s1.p<s2.p;}int main () {scanf("%d",&n);for(int i=1;i<=n;i++) {scanf("%d%d",&a[i].p,&a[i].s);a[i].S=a[i].p-a[i].s-1;}int cnt=0; int tmp;sort(a+1,a+n+1,cmp);int ans=0,L=0;int cc=1;for(int i=0;i<=M;i++) {if(i==a[cc].p) {if(a[cc].S>=0) {dp[i] = dp[a[cc].S] +1;}else dp[i] = 1;cc++;}else dp[i] = dp[i-1];ans=max(dp[i],ans);// cout<<dp[i]<<endl;}cout<<n-ans<<endl;return 0; }daima標解dp代碼7:(wlb)
#pragma warning(disable:4996) #include <iostream> #include <algorithm> #include <cmath> #include <vector> #include <string> #include <cstring> #include <queue> using namespace std; typedef long long ll; #define INF 0x3fffffffconst int maxn = 1000005;int n, nmax; int dp[maxn]; int d[maxn];//記錄能夠存活的最大值void input() {int i, a;scanf("%d", &n);nmax = 0;for (i = 1; i <= n; i++) {scanf("%d", &a);//記錄炸彈位置scanf("%d", &d[a]);//記錄該位置炸彈的范圍nmax = max(a, nmax);} }void solve() {int i;if (d[0])dp[0] = 1;int res = n;res = min(res, n - dp[0]);for (i = 1; i <= nmax; i++) {if (d[i] == 0) {dp[i] = dp[i - 1];//如果該位置沒有炸彈} else {if (d[i] >= i) {dp[i] = 1;//這個位置只剩下一個了} else {dp[i] = dp[i - d[i] - 1] + 1;//表示在該炸彈的范圍內只存活了自己,所以在之前的位置加1}}res = min(res, n - dp[i]);}printf("%d", res); }int main() {//freopen("i.txt", "r", stdin);//freopen("o.txt", "w", stdout);input();solve();//system("pause");return 0; }超時代碼:
#include<bits/stdc++.h>using namespace std; int pos[100000 + 5],b[100000 +5]; int main() {int n;scanf("%d",&n);for(int i = 1; i<=n; i++) {scanf("%d %d",&pos[i],&b[i]);}int loc,ans,minn = 0x3f3f3f3f;for(int i = n; i>=1; i--) {loc = i;ans = 0;while(loc > 1) {int pre = loc;if(pos[loc] - pos[loc-1] > b[loc]) {loc--;continue;}loc = lower_bound(pos+1,pos+loc+1,pos[loc] - b[loc]) - pos;if(loc == pre) continue;ans += (pre - loc );loc--;}minn = min(minn,ans + (n-i)); // printf("mi = %d\n",minn);}printf("%d\n",minn);return 0 ; } //4 //1 9 //3 1 //6 1 //7 4?
總結
以上是生活随笔為你收集整理的【CodeForces - 608C】Chain Reaction (二分 或 dp ,思维)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Radio.exe - Radio是什么
- 下一篇: 【HDU - 3714 】Error C