【牛客 - 318E】爱摸鱼的Dillonh(数学,暴力,细节)
題干:
“我不做人啦,jojo!”
“Dillonh起來回答問題!”
“啊?”沉迷于jojo的Dillonh又一次上課摸魚被老師抓到了,他慌忙地抬起頭看著講臺上火冒三丈的老師。
“給你一個數n,現在要找到一個集合AA,AA中若干數a1,a2,……ama1,a2,……am,使得n=a1?a2?a3?……?amn=a1?a2?a3?……?am,同時對于任意的i和j(1≤i,j≤n1≤i,j≤n)都要滿足∣∣ai?aj∣∣≤1|ai?aj|≤1,你能找到所有滿足這個條件的集合AA嗎。如果對于這個數n有無限多個可能的集合AA,那么就輸出-1,否則就輸出所有不同的集合?!比绻凵衲軞⑷说脑?#xff0c;此刻的Dillonh就已經被他的老師殺了千萬遍了。
“這...”沉迷摸魚的Dillonh自然是不會做這個題的,他現在急的滿頭大汗。作為聰明的ACMer,你能幫他解決這個問題嗎?
(對于兩個集合AA和BB,如果兩個集合內元素的個數不同的話,就認為這兩個集合是不同的;如果這兩個集合內元素個數相同的話,如果兩個集合內的元素不論以任何順序排序之后,仍然是不完全相同的話,那么就認為這兩個集合是不同的)。
輸入描述:
第一行一個數字T,代表有T組測試樣例(T<=100)
對于每組測試樣例都會輸入一個數字n,代表老師提出的問題的數。(n≤1018n≤1018)。
輸出描述:
對于每組測試樣例,第一行輸出一個“Case #x:”,x代表當前為第幾組測試樣例。如果有無限多個滿足條件的集合,第二行就輸出“-1”;否則的話,第二行輸出一個數字m,代表有m個集合是滿足條件的。接下來m行輸出這m個集合的信息,按集合內元素個數的大小從小到大輸出,每行的第一個數num代表集合內元素的個數,接下來按從小到大輸出num個數。每行的兩個數之間用一個空格隔開,行末不要有空格。示例1
輸入
復制
2 12 1輸出
復制
Case #1: 3 1 12 2 3 4 3 2 2 3 Case #2: -1解題報告:
(來自官方題解)
這是一個考驗數學思維的題目。
當滿足條件的集合內只有兩個數的時候,要么n=a*a,要么n=a*(a-1),我們可以直接對
n進行開根號運算,令cnt1 = ceil(sqrt(n)),cnt2 = floor(sqrt(n)),然后判斷cnt1 *
cnt2 是否等于n即可。
當滿足條件的集合內有大于等于三個數的時候,我們可以知道n = a * a * a * ... * (a-1)
*...*(a-1)。當a取到最大值時,應該滿足n = a * a * a,而n是小于等于1e18的,所以我
們可以知道a是小于等于1e6的,所以我們就可以暴力對a進行枚舉了,每次驗證一下是否
合法即可。
對于輸出“-1”的情況,也就只有當n=1,或者n=2^k的時候會成立,此時n可以分解為
k個2和無數個1相乘的形式,故有無數個集合。最后再按要求處理一下輸出就可以了。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define pb push_back #define pm make_pair #define fi first #define se second using namespace std; const int MAX = 2e5 + 5; const ll mod = 1e9+7; typedef long double ld; int T; ll n; vector<vector<ll> > vv; int main() {scanf("%d",&T);int cas=1;while(T--) {scanf("%lld",&n);ll x=n;while(x%2==0)x/=2;printf("Case #%d:\n",cas++);if(x==1)printf("-1\n");else {vv.clear();for(int i=1; i<=60; i++) {ll t=(ll)powl((ld)n,(ld)(1.0/i));if(t==1)continue;x=n;vector<ll> v;while(x%t==0)x/=t,v.push_back(t);while(x%(t+1)==0)x/=t+1,v.push_back(t+1);if(v.size()==i&&x==1)vv.push_back(v);}printf("%d\n",vv.size());int up = vv.size();for(int i = 0; i<up; i++) {printf("%d",vv[i].size());int upp = vv[i].size();for(int j = 0; j<upp; j++) printf(" %lld",vv[i][j]);printf("\n");}}}return 0; }總結:注意精度問題所以需要powl函數
總結
以上是生活随笔為你收集整理的【牛客 - 318E】爱摸鱼的Dillonh(数学,暴力,细节)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2021年要避免哪些理财的坑?有哪些常见
- 下一篇: 【CodeForces - 722C】D