P4397 [JLOI2014]聰明的燕姿
阿新 • • 發佈:2018-10-11
發現 輸入輸出格式 假設 main ret 一個 個數 程序 i++
P4397 [JLOI2014]聰明的燕姿
題目背景
陰天傍晚車窗外
未來有一個人在等待
向左向右向前看
愛要拐幾個彎才來
我遇見誰會有怎樣的對白
我等的人他在多遠的未來
我聽見風來自地鐵和人海
我排著隊拿著愛的號碼牌
題目描述
城市中人們總是拿著號碼牌,不停尋找,不斷匹配,可是誰也不知道自己等的那個人是誰。
可是燕姿不一樣,燕姿知道自己等的人是誰,因為燕姿數學學得好!燕姿發現了一個神奇的算法:假設自己的號碼牌上寫著數字 \(S\),那麽自己等的人手上的號碼牌數字的所有正約數之和必定等於 \(S\)。
所以燕姿總是拿著號碼牌在地鐵和人海找數字(餵!這樣真的靠譜嗎)可是她忙著唱《綠光》,想拜托你寫一個程序能夠快速地找到所有自己等的人。
輸入輸出格式
輸入格式:
輸入包含 \(k\) 組數據。 對於每組數據,輸入包含一個號碼牌\(S\)。
輸出格式:
對於每組數據,輸出有兩行,第一行包含一個整數 \(m\),表示有 \(m\) 個等的人。
第二行包含相應的 \(m\) 個數,表示所有等的人的號碼牌。
註意:你輸出的號碼牌必須按照升序排列。
說明
對於 \(100\%\) 的數據,\(k \le 100\), \(S \le 2 \times 10^9\)?? 。
唯一分解
\(S=\prod p_i^{c^i}\)
約數和\(\sigma(S)=\prod \sum_{i=0}^{c^i} p_i^i\)
然後可以直接搜索\(c\)和\(p\)
註意一些邊界情況即可
Code:
#include <cstdio> #include <algorithm> const int N=1e7; int pri[N+10],ispri[N+10],cnt,k,tot,s[N]; void init() { for(int i=2;i<=N;i++) { if(!ispri[i]) pri[++cnt]=i; for(int j=1;j<=cnt&&pri[j]*i<=N;j++) { ispri[pri[j]*i]=1; if(i%pri[j]==0) break; } } } bool check(int p,int dep) { if(p<=N) return !ispri[p]&&p>=pri[dep]; for(int i=1;pri[i]<=46340&&pri[i]*pri[i]<=p;i++) if(p%pri[i]==0) return false; return true; } void dfs(int res,int dep,int num) { if(res==1) {s[++tot]=num;return;} if(check(res-1,dep)) dfs(1,dep,(res-1)*num); if(res<pri[dep]*pri[dep]) return; dfs(res,dep+1,num); int po=pri[dep]+1,hmi=pri[dep]; while(po<=res) { if(res%po!=0) { po=po*pri[dep]+1,hmi*=pri[dep]; continue; } dfs(res/po,dep+1,num*hmi); if(po>46340) break; po=po*pri[dep]+1,hmi*=pri[dep]; } } int main() { init(); while(scanf("%d",&k)!=EOF) { tot=0; dfs(k,1,1); std::sort(s+1,s+1+tot); tot=std::unique(s+1,s+1+tot)-s-1; printf("%d\n",tot); for(int i=1;i<=tot;i++) printf("%d ",s[i]); if(tot) printf("\n"); } return 0; }
2018.10.10
P4397 [JLOI2014]聰明的燕姿