CodeForces - 1267K Key Storage(组合数学)
題目鏈接:點擊查看
題目大意:給出一個正整數num,現在將其進行除以2、除以3、除以4....的操作,直到num變為0為止,期間記錄每一次運算的余數,將其排序后得到一個集合,現在問有多少不同的數字經相同處理后的集合與num的集合相等
題目分析:如果想讓余數組成的集合相等,需要排列組合計算個數,比如正常的全排列,若是有n個數,那么對于第一個位置,可以有n種選擇,對于第2個數,可以有n-1種選擇,依次類推得到的是全排列的公式n!,但是考慮到這個題目對于每個位置可供選擇的余數都是有限制的,所以不能貿然直接用全排列去計算,不過我們可以借助全排列的思想去進行實現,因為越往后的限制越小,所以我們可以從第一位進行選擇,因為對于第i位的余數,可以選擇的范圍是0~i(第i位的余數是被除數除以(i+1)得到的),所以先將前面的方案數確定,利用全排列的思想依次確定后續的方案數,最后記得去重,因為有重復元素,每種相同的元素個數為cnt,則會重復計算cnt!次,因為這cnt個相同元素內部全排列后的結果都是一樣的,最后這個題目還有一個細節,就是第一位上肯定不能為0,因為0不可能作為被除數出現在這個題目中,最后一次的除法運算肯定是商為0,余數為其本身才能達到終止循環,這樣一來答案需要減去最后一位為0的方案數,最后ans-1就是答案了,減去當前這個數的本身
2020.9.3更新:
昨天訓練的時候碰到的原題,最后那個細節,也就是最后一個位置忘記不能是零了,怎么都跑不出樣例,就非常自閉了,還有去年寫的代碼,也是仿照別人的代碼寫的,就是非常的丑,關于階乘和統計多少個小于當前位置的數,用前綴和不香嘛,后面附上重構后的代碼
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e3+100;vector<int>v;void init(LL x) {v.clear();for(int i=2;x;i++){v.push_back(x%i);x/=i;}sort(v.begin(),v.end()); }LL solve() {LL ans=1;for(int i=0;i<v.size();i++){int cnt=0;for(int j=0;j<v.size();j++){if(v[j]<i+2)cnt++;}ans*=cnt-i;}LL fac=1;for(int i=0;i<v.size()-1;i++){if(v[i]==v[i+1])ans/=++fac;elsefac=1;}return ans; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int w;cin>>w;while(w--){LL num;scanf("%lld",&num);init(num);LL ans=solve();if(v[0]==0){v.erase(v.begin());ans-=solve();}printf("%lld\n",ans-1);}return 0; }更新:
#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;const int M=20;vector<int>node;LL sum[M],fac[M],cnt[M];void init(LL n) {node.clear();for(int i=2;n;i++){node.push_back(n%i);n/=i;}sort(node.begin(),node.end()); }LL solve() {LL ans=1;memset(sum,0,sizeof(sum));memset(cnt,0,sizeof(cnt));for(int num:node){sum[num]++;cnt[num]++;}for(int i=1;i<M;i++)sum[i]+=sum[i-1];for(int i=1;i<=node.size();i++)ans*=(sum[i]-(i-1));for(int i=0;i<M;i++)ans/=fac[cnt[i]];return ans; }int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);fac[0]=1;for(int i=1;i<M;i++)fac[i]=fac[i-1]*i;int w;cin>>w;while(w--){LL n;scanf("%lld",&n);init(n);LL ans=solve();if(node.front()==0){node.erase(node.begin());ans-=solve();}printf("%lld\n",ans-1);}return 0; }?
總結
以上是生活随笔為你收集整理的CodeForces - 1267K Key Storage(组合数学)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 727D T-
- 下一篇: CodeForces - 510E Fo