1. 程式人生 > 實用技巧 >訓練賽後補題 04

訓練賽後補題 04

2020-06-29 個人訓練賽後補題

補題補到心態炸裂……嗚嗚嗚怎麼沒寫的這麼多啊

我好菜

好了開始補題:

QAQ完全沒發現自己錯在哪的第一個提交

WA的程式碼:

 1 #pragma warning (disable:4996)
 2 #include <iostream>
 3 #include<algorithm>
 4 #include<stdio.h>
 5 #include<math.h>
 6 #include<string.h>
 7 #include<string>
 8 #define
MAX1 100005 /*1e5 + 5*/ 9 #define MAX2 1000000005 /*le9 + 5*/ 10 #define MAX3 200005 /*1e5 + 5*/ 11 #define MAX4 5005 /*5e4 + 5*/ 12 #define T2 27 13 #define T3 18 14 using namespace std; 15 typedef long long int ll; 16 #define MOL 998244353 17 18 int main() { 19 int n, k, a[MAX4] = { 0
}, i; 20 while (scanf("%d %d", &n, &k) != EOF) { 21 for (i = 1; i <= n; ++i) { 22 scanf("%d", &a[i]); 23 } 24 int j, t = 0, ans, flag; 25 ans = 0; 26 for (i = 1; i <= n;) { 27 //cout << i << ":" << a[i] << endl;
28 j = 0; 29 flag = 0; 30 if (a[i]) { 31 i += k; //pass 32 ans++; //help+1 33 } 34 else { 35 flag = 1; 36 t = i; 37 j = i + k - 1; 38 while (j > t) { 39 if (a[j]) { 40 i = j; 41 flag = 0; 42 break; 43 } 44 j--; 45 } 46 } 47 if (flag) { 48 break; 49 } 50 } 51 if (flag || ans == 0)printf("-1\n"); 52 else printf("%d\n", ans); 53 } 54 return 0; 55 }

我太難了55555

////-------------------------------------

去了原題cf看了樣例,明白我錯在哪了……a[i]=0的時候檢索區域大小不應該是k-1,應該是2k-1……

6 2
0 1 1 0 0 1

這個資料就不能通過……

可見測試資料範圍的重要性

////-------------------------------------

我又又又又叕叒雙WA了,WA在了test 5

這次的主函式:

 1 int main() {
 2     int n, k, a[MAX4] = { 0 }, i;
 3     while (scanf("%d %d", &n, &k) != EOF) {
 4         for (i = 1; i <= n; ++i) {
 5             scanf("%d", &a[i]);
 6         }
 7         int j, t = 0, ans, flag;
 8         ans = 0;
 9         for (i = 1; i <= n;) {
10             //cout << i << ":" << a[i] << endl;
11             j = 0;
12             flag = 0;
13             if (a[i]) {
14                 i += k;
15                 ans++;        //help+1
16             }
17             else {
18                 flag = 1;
19                 if (i > k)
20                     t = i - k;
21                 else 
22                     t = i;
23                 if (i + k - 2 < n)
24                     j = i + k - 1;
25                 else j = n;
26                 while (j > t) {
27                     if (a[j]) {
28                         i = j + k;
29                         ans++;
30                         flag = 0;
31                         break;
32                     }
33                     j--;
34                 }
35             }
36             if (flag) {
37                 break;
38             }
39         }
40         if (flag || ans == 0)printf("-1\n");
41         else printf("%d\n", ans);
42     }
43     return 0;
44 }

這次的失敗樣例是:

【太長了網站沒給全】

1000 100 0 1……正答6,輸出8

emmmm我瞅瞅咋多了

emmm這份程式碼邏輯有個隱患,就是:程式碼本身是每次往後檢索最遠的接應點,但是對於樣例,可能部分挨著的接應點能滿足更少的數量……總之就是極端樣例不通過。

so我去看了題解……我真的真的恨不熟練貪心。

還能怎麼辦呢,學唄。

////------------------堅定自己程式碼邏輯有實現可能的我賊心不死,又去修改原先的程式碼了

這次能通過了,但是超時了【泣不成聲】

以下是在樣例10超時的程式碼:

 1 #pragma warning (disable:4996)
 2 #include <iostream>
 3 #include<algorithm>
 4 #include<stdio.h>
 5 #include<math.h>
 6 #include<string.h>
 7 #include<string>
 8 #define MAX1 100005            /*1e5 + 5*/
 9 #define MAX2 1000000005        /*le9 + 5*/
10 #define MAX3 200005            /*1e5 + 5*/
11 #define MAX4 5005            /*5e4 + 5*/
12 #define T2 27
13 #define T3 18
14 using namespace std;
15 typedef long long int ll;
16 #define MOL 998244353
17 
18 int main() {
19     int n, k, a[MAX4] = { 0 }, i, flag = 0;
20     while (scanf("%d %d", &n, &k) != EOF) {
21         for (i = 1; i <= n; ++i) {
22             scanf("%d", &a[i]);
23         }
24         int rf, lf = 0, ans, flag = 0;
25         ans = 0;
26         for (i = 1; i <= n;) {        //從前方洞穴往後檢測
27             //失誤點:第一個風洞非必要選擇
28             //cout << i << ":" << a[i] << endl;
29             rf = 0;
30             flag = 1;                //假設前後風洞都不能使當前洞可走
31             if (i > k)                //前方最遠風洞距離限制
32                 lf = i - k;
33             else
34                 lf = 1;
35             if (i + k - 2 < n)        //後方最遠風洞距離限制
36                 rf = i + k - 1;
37             else
38                 rf = n;
39             while (rf >= lf) {        //從後方往前檢測
40                 if (a[rf]) {        //檢測到風洞
41                     i = rf + k;        //下一監測點為風洞影響範圍外鄰點
42                     ans++;            //所用風洞數+1
43                     flag = 0;        //這一段路可走了
44                     break;            //暫停檢測,進入下一監測點
45                 }
46                 rf--;
47             }
48             //cout << "check finished" << endl;//test
49             if (flag) {                    //出現沒有前後風洞能接力的洞,退出檢測
50                 break;
51             }
52         }
53         if (flag || ans == 0)printf("-1\n");
54         else printf("%d\n", ans);
55     }
56     return 0;
57 }

emmmm接下來按照這個邏輯優化試試

總結一下邏輯規律:每次找出範圍內的最後一個風洞,不過是從前往後

臥槽,這……這本質上就是貪心啊【驚】

////----------------7.04更新!我終於AC辣!!!

尤其是,我發現我離AC只有一步之遙——沒錯把其中一個順序調換一下,就不需要多餘的檢測了!

下面是AC程式碼,我太難了55555

不過AC了真高興

 1 #pragma warning (disable:4996)
 2 #include <iostream>
 3 #include<algorithm>
 4 #include<stdio.h>
 5 #include<math.h>
 6 #include<string.h>
 7 #include<string>
 8 #define MAX1 100005            /*1e5 + 5*/
 9 #define MAX2 1000000005        /*le9 + 5*/
10 #define MAX3 200005            /*1e5 + 5*/
11 #define MAX4 5005            /*5e4 + 5*/
12 #define T2 27
13 #define T3 18
14 using namespace std;
15 typedef long long int ll;
16 #define MOL 998244353
17 
18 int main() {
19     int n, k, a[MAX4] = { 0 }, s[MAX4] = { 0 }, i, flag = 0;
20     while (scanf("%d %d", &n, &k) != EOF) {
21         for (i = 1; i <= n; ++i) {
22             scanf("%d", &a[i]);
23             s[i] = s[i - 1] + a[i];         //前幾個洞中有多少風洞
24         }
25         int rf, lf = 0, ans, flag = 0;
26         ans = 0;
27         for (i = 1; i <= n;) {              //從前方洞穴往後檢測
28         //失誤點:第一個風洞非必要選擇
29         //cout << i << ":" << a[i] << endl;
30             rf = 0;
31             flag = 1;                       //假設前後風洞都不能使當前洞可走
32             if (i > k - 1)                  //前方最遠風洞距離限制
33                 lf = i - k + 1;
34             else
35                 lf = 1;
36             if (i + k - 2 < n)              //後方最遠風洞距離限制
37                 rf = i + k - 1;
38             else
39                 rf = n;
40             if (s[rf] - s[lf - 1] == 0)     //距離限制範圍內無風洞,退出檢測
41                 break;
42             else 
43                 while (rf >= lf) {          //從後方往前檢測
44                     if (a[rf]) {            //檢測到風洞
45                         i = rf + k;         //下一監測點為風洞影響範圍外鄰點
46                         ans++;              //所用風洞數+1
47                         flag = 0;           //這一段路可走了
48                         break;              //暫停檢測,進入下一監測點
49                     }
50                     rf--;
51                 }
52             //cout << "check finished" << endl;//test
53         }
54         if (flag || ans == 0)printf("-1\n");
55         else printf("%d\n", ans);
56     }
57     return 0;
58 }

////------------------7.06更新……隊裡大佬說自己打出題要比照著題解打好很多,嘿嘿嘿我也這麼覺得。

我這次認真查了一下貪心

強烈安利一個大佬哦,部落格寫得超級好理解

網址:https://blog.csdn.net/jxhaha/article/details/78762412

另外我還做了些筆記:

活動選擇:對於互斥不可重複活動,始終選取結束時間最早的活動作為解集合成員,每次抽取結束時間最早的活動。

0 - 1揹包:F[i,j] = max(F[i-1,j],F[i-1,j-Wi]+Vi)    適用:每個物體只抽一次取最大重量方案

完全揹包:F[i,j]=max(f[i-1,j], f[i,j-Wi]+Vi)      適用:能多次選擇同一物體取最大重量

多重揹包:F[i,j] = max(F[i-1,j],F[i, j-Wi*k]+Vi*k    適用:規定次數內可選同一物品時取最大重量

膜拜大佬!