1. 程式人生 > 實用技巧 >7.20試機測 T3 階乘之和 暴力AC題解

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函式)

數字 0 1 2 3 4 5 6 7 8 9 10
階乘 1 1 2 6 24 120 720 5040 40320 362880 3628800

看到資料範圍,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