題目連結 : 12218.pdf (onlinejudge.org)
題目大意 : 問這個數字的排列,子集合共有幾個質數
思路: 建立質數表,暴力法,枚舉所有子集合,每枚舉一種子集合,就嘗試所有子集合排列組合。子集合枚舉方式可參考Leetcode subset那題。
有其他作法,雖然用2進位很潮。
代碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e7;
bool np[N];
void init(){ // 歐式篩
for(int i = 2; i <= sqrt(N); ++i){
for(int j = 2*i; j < N; j += i)
np[j] = 1;
}
}
int main() {
//cin.tie(0); ios::sync_with_stdio(false);
init();
int T;
cin >> T;
np[1] = np[0] = 1;
for(int t = 0; t < T; ++t){
string s;
cin >> s;
sort(s.begin(), s.end());
set<int> res;
for(int i = 1; i < 1<<s.size(); ++i){ // 枚舉所有subset,1取 0不取,e.g 001 表示第0個取。 第1,2個都不取
string tmp = "";
for(int j = 0; j < (int)s.size(); ++j){ // 這邊去看i有哪幾個是1,設1的要取。
if(i>>j&1) tmp += s[j]; // 也可以寫成 if((1<<j) & i)
}
do{
int num = stoi(tmp);
if(np[num] || res.count(num)) continue;
res.insert(num);
}while(next_permutation(tmp.begin(), tmp.end()));
}
cout << res.size() << "\n";
}
}
/**
4
17
1276543
9999999
011
**/
文章標籤
全站熱搜

挖,剛考完這一屆(CPE),正要把不會的題目弄到懂,昨天才查不到題解,今天就出來了,感謝!
謝謝,不過這次的第七題蠻難的,不想寫Orz 是說中山大學YT有題解,可以去那邊看看~
想請問 if(i>>j&1) tmp += s[j];的部分是甚麼原理可以找出排列組合的? 中山大學的YT講解看了好幾遍實在是不懂
if(i>>j&1) tmp += s[j]; 這邊並不是找出排列組合,找出排列組合在這next_permutation(tmp.begin(), tmp.end()); 這行是找出tmp的排列組合 比如tmp = 123, 那麼這行產生的tmp所有可能共有6種: 123, 132, 213, 231, 312, 321 首先了解 if(i>>j&1) tmp += s[j];前 先了解下面這個for迴圈在幹嘛 for(int i = 1; i < 1<<s.size(); ++i) 這個for是走訪所有長度為s.size()的2進位 舉例: s.size() = 2, 則走 01, 10, 11對吧(因為我i=1, 所以不走00) 那這2進位要拿來幹嘛呢? 你可以把它想成marked array。假設1為mark, 0為unmark 舉例: 01 是甚麼 代表index從0的 arr[0] = 1, arr[1] = 0 那這是幹嘛用? 舉例 s = "12" 問s的子集合有哪些 子集合 = {"", "1", "2", "12"} 如果你今天的mark array 為01 代表 第0個值要取, 第1個值不取 (右邊看到左邊) 以 s = "12" 的例子 第0個值要取, 第1個值不取 = "12" = "2" 而這行 (i>>j&1) 也等於 ((i & (1<<j)) == 1) 也就是檢查i的第j個位元是否為1 所以假設i = 1的時候, s = "12" for(int j = 0; j < (int)s.size(); ++j){ if(i>>j&1) tmp += s[j]; } 結果 tmp = "2" 你可以再跑其他i想想 tmp 會是甚麼