7.20試機測 T3 階乘之和 暴力AC題解


7.20試機測  T3 階乘之和 暴力AC題解

題外話:此乃本蒟蒻發表的第一篇題解,大家多多關照,支持一下,謝謝


題面

3、階乘之和(sum.pas/in/out)

問題描述: 給定一個非負整數 n,請你判斷 n 是否可以由一些非負整數的階乘相加得到。

問題輸入: 有若干組數據。每行一個整數 n,保證 n<1000000。 以負數結束輸入。

問題輸出: 對於每組數據輸出一行,若可以則輸出‘YES’,否則輸出‘NO’。

輸入樣例: 9 -1

樣例輸出: YES


分析

這個題嘛

大概了解了一下題意,就是給出n,判斷n能不能被幾個數的階乘加起來。(雖然題目沒有說清楚數字能不能重復,但是我們知道1的階乘是1,如果數字可以重復的話,那么任何n都是YES了,所以我推測所選數字不能重復)


 

題目讓輸入多組數據,我們先針對一個數據進行操作,在結尾再弄關於輸入多組數據的問題…………

下面算出一些較小數的階乘(千萬不要忘記0)(這一步可以在Excel完成,用FACT函數)

 

看到數據范圍, n<1000000,可以了解到所選的數字應該在0~9里。

那么,n的最大值就確定了,即0~9的階乘之和(1+1+2+6+24+...+40320+362880=409114)

 

也就是說,只要n的值超過了409114,那么這個n就不符合條件,可以提前判斷一部分n是不是NO。

還有,0的階乘是1,那么如果n的值為0,就沒有非負整數滿足n,也是直接NO。

if(n>409114 || n==0) cout<<"NO"<<endl;

 


 下面怎么辦呢,暴力?!

在這里,我還沒有學一些什么神奇01背包,二進制什么玩意……

我就簡簡單單地用幾個for循環來搜出所有情況吧。

 

先開一個數組(第一個開0是防止有??的情況   其實第一個完全可以不開0,不開0還節省了時間)

long long x[11]= {0,1,1,2,6,24,120,720,5040,40320,362880};

 

我們知道,題目給定一個n,這個n可能由上面數組中的1個數相加得到,也可能是2個,也可能是多個……

(比如n=4時,n是1+1+2,由數組中的3個數相加得到;n=25時,則為1+24,由數組中的2個數相加得到)

 

那么,我們先假設n由上面選1個數得到,則可以

for(int a=0; a<11; ++a) if(x[a]==n) { cout<<"YES"<<endl; }

 

如果一個數不行,那就看看2個數加起來能不能得到n

這里防止有判重的情況,就讓b=a+1,還節省了時間。

for(int a=0; a<11; ++a) for(int b=a+1; b<11; ++b) if(x[a]+x[b]==n) { cout<<"YES"<<endl; }

 

下面以此類推……直到10個數的時候

for(int a=0; a<11; ++a)
for(int b=a+1; b<11; ++b) for(int c=b+1; c<11; ++c) for(int d=c+1; d<11; ++d) for(int e=d+1; e<11; ++e) for(int f=e+1; f<11; ++f) for(int g=f+1; g<11; ++g) for(int h=g+1; h<11; ++h) for(int i=h+1; i<11; ++i) for(int j=i+1; j<11; ++j) if(x[a]+x[b]+x[c]+x[d]+x[e]+x[f]+x[g]+x[h]+x[i]+x[j]==n) { cout<<"YES"<<endl; }

 

這樣就行了?此處忽略了一個地方,假設n由5個數相加就能得到,那么下面的6次,7次循環再執行豈不是浪費掉了時間嘛。

所以,我們開一個布爾變量,用來判斷n是不是已經被配對

bool yes=false;

 


 

好了,現在我們可以研究輸入多組數據的問題了,因為不研究這個,布爾變量就沒法展現它的作用。

題意說輸入負數的時候結束程序(千萬不要被樣例迷惑了,不一定是-1結束程序)

那么,可以用while循環輸入數據。

每輸入一個n,就對n執行一次下面的操作。 直到n<0時,return 0 結束程序。

<0

int main() { while(scanf("%d",n) && n>=0) { yes=false; //此處往下寫程序,每次當n配對時,把布爾變量變成true。
 }
  return 0; }

 

當n被配對時,變量yes的值為true。我們可以在程序中瘋狂檢測 yes的值,只要是true就立即讓它輸出“YES”,然后扔掉此時的n,再對下一個數字n進行操作。

 

具體操作如下(拿n由4個數相加得到 舉例):

 for(int a=0; a<11; ++a) { for(int b=a+1; b<11; ++b) { for(int c=b+1; c<11; ++c) { for(int d=c+1; d<11; ++d) if(x[a]+x[b]+x[c]+x[d]==n) { cout<<"YES"<<endl; yes=true; //只要n被配對成功,就把布爾設為true break; } if(yes==true) break; //讓被配對成功的n 一路順風,跳出循環 } if(yes==true) break; } if(yes==true) break; } if(yes==true) continue;  //此時的 continue 與 while 讀入操作在同一層。這樣就可以讀入下一個n了

 

這樣看起來好像有點麻煩,但是我覺得理解起來不難吧qwq.

 

最后當10次循環都走一遍,結果n沒有找到合適的數字,就在末尾輸出“NO”.

 


AC代碼:

 1 /*---------------------------------  2  *Title number: 7.20 試機測 T3 階乘之和  3  *Creation date: 2020-07-20 afternoon  4  *By: EdisonBa  5  *-------------------------------*/
 6 #include<iostream>
 7 #include<cstdio>
 8 #include<cmath>
 9 #include<cstdlib>
 10 #include<cstring>
 11 #include<algorithm>
 12 using namespace std;  13 
 14 long long x[11]= {0,1,1,2,6,24,120,720,5040,40320,362880};  15 long long n;  16 bool yes=false;  17 
 18 int main()  19 {  20     while(cin>>n && n>=0)  21  {  22         yes=false;  //每一次對n操作都要重置一下布爾變量 yes  23         
24 //下面判一下最大值和0 25
26 if(n>409114 || n==0) 27 { 28 cout<<"NO"<<endl; 29 continue; 30 } 31
32 //下面進行第 1 次循環 33
34 for(int a=0; a<11; ++a) 35 if(x[a]==n) 36 { 37 cout<<"YES"<<endl; 38 yes=true; 39 break; 40 } 41 42 if(yes==true) continue; 43
44 //下面進行第 2 次循環 45
46 for(int a=0; a<11; ++a) 47 { 48 for(int b=a+1; b<11; ++b) 49 50 if(x[a]+x[b]==n) 51 { 52 cout<<"YES"<<endl; 53 yes=true; 54 break; 55 } 56 if(yes==true) break; 57 } 58 59 if(yes==true) continue; 60
61 //下面進行第 3 次循環 62
63 for(int a=0; a<11; ++a) 64 { 65 for(int b=a+1; b<11; ++b) 66 { 67 for(int c=b+1; c<11; ++c) 68 69 if(x[a]+x[b]+x[c]==n) 70 { 71 cout<<"YES"<<endl; 72 yes=true; 73 break; 74 } 75 if(yes==true) break; 76 } 77 if(yes==true) break; 78 } 79 80 if(yes==true) continue; 81
82 //下面進行第 4 次循環 83
84 for(int a=0; a<11; ++a) 85 { 86 for(int b=a+1; b<11; ++b) 87 { 88 for(int c=b+1; c<11; ++c) 89 { 90 for(int d=c+1; d<11; ++d) 91 if(x[a]+x[b]+x[c]+x[d]==n) 92 { 93 cout<<"YES"<<endl; 94 yes=true; 95 break; 96 } 97 if(yes==true) break; 98 } 99 if(yes==true) break; 100 } 101 if(yes==true) break; 102 } 103 104 if(yes==true) continue; 105
106 //下面進行第 5 次循環 107
108 for(int a=0; a<11; ++a) 109 { 110 for(int b=a+1; b<11; ++b) 111 { 112 for(int c=b+1; c<11; ++c) 113 { 114 for(int d=c+1; d<11; ++d) 115 { 116 for(int e=d+1; e<11; ++e) 117 if(x[a]+x[b]+x[c]+x[d]+x[e]==n) 118 { 119 cout<<"YES"<<endl; 120 yes=true; 121 break; 122 } 123 if(yes==true) break; 124 } 125 if(yes==true) break; 126 } 127 if(yes==true) break; 128 } 129 if(yes==true) break; 130 } 131 132 133 if(yes==true) continue; 134
135 //下面進行第 6 次循環 136
137 for(int a=0; a<11; ++a) 138 { 139 for(int b=a+1; b<11; ++b) 140 { 141 for(int c=b+1; c<11; ++c) 142 { 143 for(int d=c+1; d<11; ++d) 144 { 145 for(int e=d+1; e<11; ++e) 146 { 147 for(int f=e+1; f<11; ++f) 148 if(x[a]+x[b]+x[c]+x[d]+x[e]+x[f]==n) 149 { 150 cout<<"YES"<<endl; 151 yes=true; 152 break; 153 } 154 if(yes==true) break; 155 } 156 if(yes==true) break; 157 } 158 if(yes==true) break; 159 } 160 if(yes==true) break; 161 } 162 if(yes==true) break; 163 } 164 165 if(yes==true) continue; 166
167 //下面進行第 7 次循環 168
169 for(int a=0; a<11; ++a) 170 { 171 for(int b=a+1; b<11; ++b) 172 { 173 for(int c=b+1; c<11; ++c) 174 { 175 for(int d=c+1; d<11; ++d) 176 { 177 for(int e=d+1; e<11; ++e) 178 { 179 for(int f=e+1; f<11; ++f) 180 { 181 for(int g=f+1; g<11; ++g) 182 if(x[a]+x[b]+x[c]+x[d]+x[e]+x[f]+x[g]==n) 183 { 184 cout<<"YES"<<endl; 185 yes=true; 186 break; 187 } 188 if(yes==true) break; 189 } 190 if(yes==true) break; 191 } 192 if(yes==true) break; 193 } 194 if(yes==true) break; 195 } 196 if(yes==true) break; 197 } 198 if(yes==true) break; 199 } 200 201 if(yes==true) continue; 202
203 //下面進行第 8 次循環 204
205 for(int a=0; a<11; ++a) 206 { 207 for(int b=a+1; b<11; ++b) 208 { 209 for(int c=b+1; c<11; ++c) 210 { 211 for(int d=c+1; d<11; ++d) 212 { 213 for(int e=d+1; e<11; ++e) 214 { 215 for(int f=e+1; f<11; ++f) 216 { 217 for(int g=f+1; g<11; ++g) 218 { 219 for(int h=g+1; h<11; ++h) 220 if(x[a]+x[b]+x[c]+x[d]+x[e]+x[f]+x[g]+x[h]==n) 221 { 222 cout<<"YES"<<endl; 223 yes=true; 224 break; 225 } 226 if(yes==true) break; 227 } 228 if(yes==true) break; 229 } 230 if(yes==true) break; 231 } 232 if(yes==true) break; 233 } 234 if(yes==true) break; 235 } 236 if(yes==true) break; 237 } 238 if(yes==true) break; 239 } 240 241 if(yes==true) continue; 242
243 //下面進行第 9 次循環 244
245 for(int a=0; a<11; ++a) 246 { 247 for(int b=a+1; b<11; ++b) 248 { 249 for(int c=b+1; c<11; ++c) 250 { 251 for(int d=c+1; d<11; ++d) 252 { 253 for(int e=d+1; e<11; ++e) 254 { 255 for(int f=e+1; f<11; ++f) 256 { 257 for(int g=f+1; g<11; ++g) 258 { 259 for(int h=g+1; h<11; ++h) 260 { 261 for(int i=h+1; i<11; ++i) 262 263 if(x[a]+x[b]+x[c]+x[d]+x[e]+x[f]+x[g]+x[h]+x[i]==n) 264 { 265 cout<<"YES"<<endl; 266 yes=true; 267 break; 268 } 269 if(yes==true) break; 270 } 271 if(yes==true) break; 272 } 273 if(yes==true) break; 274 } 275 if(yes==true) break; 276 } 277 if(yes==true) break; 278 } 279 if(yes==true) break; 280 } 281 if(yes==true) break; 282 } 283 if(yes==true) break; 284 } 285 286 if(yes==true) continue; 287
288 //下面進行第 10 次循環 289
290 for(int a=0; a<11; ++a) 291 { 292 for(int b=a+1; b<11; ++b) 293 { 294 for(int c=b+1; c<11; ++c) 295 { 296 for(int d=c+1; d<11; ++d) 297 { 298 for(int e=d+1; e<11; ++e) 299 { 300 for(int f=e+1; f<11; ++f) 301 { 302 for(int g=f+1; g<11; ++g) 303 { 304 for(int h=g+1; h<11; ++h) 305 { 306 for(int i=h+1; i<11; ++i) 307 { 308 for(int j=i+1; j<11; ++j) 309 if(x[a]+x[b]+x[c]+x[d]+x[e]+x[f]+x[g]+x[h]+x[i]+x[j]==n) 310 { 311 cout<<"YES"<<endl; 312 yes=true; 313 break; 314 } 315 if(yes==true) break; 316 } 317 if(yes==true) break; 318 } 319 if(yes==true) break; 320 } 321 if(yes==true) break; 322 } 323 if(yes==true) break; 324 } 325 if(yes==true) break; 326 } 327 if(yes==true) break; 328 } 329 if(yes==true) break; 330 } 331 if(yes==true) break; 332 } 333 334 if(yes==true) continue; 335
336 // 10次循環完畢,若n沒有合適的數字,輸出"NO" 337 338 cout<<"NO"<<endl; 339 340 } 341 342 return 0; 343 }

 

 https://www.luogu.com.cn/record/35414283

 

 

(此代碼對於 第10個毒瘤點來說 能過就是奇跡)


 

這份代碼,顯然不是最優解(第10個測試點的時間快要爆了),如果把x數組里的0刪去,可能時間會稍微短那么幾毫秒。

但是這個理解起來很容易,只要有充足的時間就能寫出來(大概半個多小時)。

我覺得這個代碼的關鍵就是在每次大循環中,下層的for的變量值是上層的變量值+1(無法表述啊這)

-----------------------------------------------------------------------------------------------------------------------------------------------

看圖:

 

 -----------------------------------------------------------------------------------------------------------------------------------------------

這樣節省了大部分時間,也防止出現了判重的情況,使得多次大循環順利過測試點。


 感謝您觀看此題解。

這是本蒟蒻發表的第一篇題解,豈不妙哉?!

希望在接下來的時間里,大家共同成長,共同進步,多多交流,共創輝煌!

 

EdisonBa

2020/7/20

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM