gotutiyan’s blog

競技プログラミングをやったりopenframeworksでお絵かきをしたりしています。

ACM-ICPC 「月曜土曜素因数」

2008のB問題です。

問題
Monday-Saturday Prime Factors | Aizu Online Judge
素数とは、「1と自分以外に約数を持たないもの」です。普段はこれを「すべての自然数」について考えていますが、これを「7で割ると1または6余る数の集合」に絞って考えるとどうなるかという問題です。

解説
この問題は以下のステップを踏みます。
1 「7で割ると1または6余る数の集合」を作る(月曜土曜数の配列 ms
2 作った集合を元に、月曜土曜素数の集合をさらに作る (月曜土曜素数の配列 msprime

3 各入力に対して月曜土曜素数で割っていき、素因数になるかどうか調べる(月曜土曜素因数)

ステップ1
今回、与えられるq個のデータの上限は高々300000未満であることに注意です。
7で割ると1または6余る集合は、
・( i % 7==1 || i % 7==6) となるような i を集める
・iを増やしながら、7 * i + 1 と 7 * i + 6 を集める
で作ることができます。僕は後者で行い、msという配列に格納しました。

ステップ2
素数判定をするにあたり、
・Nの素数が存在する時、ルートN 以下しかの値しか存在しない
ということは必須です。

よって、すべての月曜土曜数 ms[i] について、sqrt(ms[i]) 以下のms[j]で割っていき、一度も割りきれなければそれは月曜土曜素数です。これをmsprime[] に格納します。

スッテプ3
入力に対して、msprime[i] で割ってみて、割り切れたらその都度出力します。

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <utility>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <cmath>
 
#define rep(i,j,k) for(int i=(int)j;i<(int)k;i++)
#define itrep(i,x) for(auto i=(x).begin(); i!=(x).end();i++)
#define Sort(x) sort((x).begin(),(x).end())
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define vec vector
#define INF INT_MAX
#define INFL 1e18
#define MOD 1000000007
#define pb push_back
#define MP make_pair
#define PI 3.1415926535
typedef long long int ll;
typedef std::pair<int,int> P;
int D=1;
int dx[4]={0,1,0,-1},dy[4]={-1,0,1,0};
 
using namespace std;
 
int main(){
 //msが月曜土曜数、msprimeが月曜土曜素数
    vector<int> ms,msprime;
 
        //ステップ1
        for(int i=0;;i++){
            if(i==0)ms.pb(7*i+6); //1は月曜土曜数にはならない
            else {
                if(7*i+1>=300000)break;
                ms.pb(7*i+1);
                ms.pb(7*i+6);
            }
        }
         
        //ラムダ式を使って、月曜土曜素数の判定関数を作る
        auto isPrime=[&](int x){
            for(int i=0;(ms[i]<=sqrt(x)+1);i++){
                if(x%ms[i]==0){
                    return false;
                }
            }
            return true;
        };
        
  //msprimeに素数を格納する
        rep(i,0,ms.size()){
            if(isPrime(ms[i])) msprime.pb(ms[i]);
        }
 
 
    int n;
    while(cin>>n && n!=1){
        cout<<n<<":";
 
        rep(i,0,msprime.size()){
            if(n%msprime[i]==0){  msprime[i]で割れたらその都度出力
                cout<<" "<<msprime[i];
            }
        }
        cout<<endl;
 
    }
 
    return 0;
}