L - Little Difference Gym - 101612L(二分答案)

 題目鏈接:http://codeforces.com/gym/101612/attachments

題解:

先考慮到特殊情況:如果該數是n的次冪的話,肯定能分解成任意個1與對應個2的乘積,此時輸出-1。

在考慮下題意,該數只能被分解成a^len或a^i*(a+1)*(len-i),由於n達到1e18,與2的60次方接近,即分解式中最多包含60位左右,不妨枚舉到64,那麼我們可以二分每個分解式的因子個數,即len,二分答案更改標誌爲a^i<=n,只有這樣才能保證n能被只由n分解或者被a和a+1分解。(仔細想一下,這樣的思路是對的,因爲只要對應分解式中的因子個數固定,該分解方式一定是唯一的或者沒有)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,tot,MAP[100][100];

int ok(ll x,int len)//len個x是否滿足小於等於n的條件
{
    ll sum=1;
    for(int i=1;i<=len;i++){
        if(n/sum>=x)sum*=x;
        else return 0;
    }
    return 1;
}
int judge(ll a,int len1,ll b,int len2)//len1個a和len2個b的乘積是否爲n
{
    ll sum=1;
    for(int i=1;i<=len1;i++){
        if(n/sum>=a)sum*=a;
        else return 0;
    }
    for(int i=1;i<=len2;i++){
        if(n/sum>=b)sum*=b;
        else return 0;
    }
    if(sum==n)return 1;
    return 0;
}
void add(ll a,int len1,ll b,int len2)//添加答案
{
    ++tot;
    MAP[tot][0]=len1+len2;
    for(int i=1;i<=len1;i++)
        MAP[tot][i]=a;
    for(int i=1;i<=len2;i++)
        MAP[tot][i+len1]=b;
}
int main()
{
    freopen("little.in", "r", stdin);
    freopen("little.out", "w", stdout);
    cin>>n;
    ll m=n;
    while(m%2==0)m/=2;
    if(m==1){            //只要是2的次冪,就可以分解成2和任意個1的乘積,即無窮種分解方法,輸出-1
        cout<<"-1"<<endl;
        return 0;
    }
    for(int len=1;len<=64;len++){
        ll l=2,r=n,ans=-1;
        while(l<=r){
            ll mid=(l+r)/2;
            if(ok(mid,len)){
                ans=mid;
                l=mid+1;
            }
            else
                r=mid-1;
        }
        if(ans==-1)
            break;
        for(int i=1;i<=len;i++){
            if(judge(ans,i,ans+1,len-i)){
                add(ans,i,ans+1,len-i);
            }
        }
    }
    cout<<tot<<endl;
    for(int i=1;i<=tot;i++){
        cout<<MAP[i][0]<<" ";
        for(int j=1;j<=MAP[i][0];j++){
            cout<<MAP[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章