UVALive 6198 A Terribly Grimm Problem

题目大意是


给出L,H      10^10范围

为[L, H]这个连续的整数区间寻找一个序列。

序列的长度要跟[L, H]一样

然后序列中的数都是素数,并且互不相同

并且序列中第i个数 要求是L + i -1的一个素因子 

最后要求序列的字典序最小


然后可以看到L,H很大

但是我们需要注意的是,这个序列长度肯定不会很大

太大了肯定满足不了题目的要求。


所以这个整数区间的数我们可以一个一个的,先把每个数都素因子分解了,放起来。

然后就发现。 这不就是二分图匹配么。

但是题目求的是字典序最小。

所以我们就对每个数。

对其所有的素因子,尝试改变匹配,然后寻找增广路。

如果能找到。就固定这条边


 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#define MAXN 111111
#define N 505
using namespace std;
bool tag[MAXN];
int p[MAXN];
int cnt;
int mark[5555], used[5555];
int cx[N], cy[5555];
vector<int>g[N];
int ans[N];
int m, up;
long long l, r;
long long a[MAXN];
set<long long>s;
map<long long, int> id;
void getprime()
{
    cnt = 0;
    tag[1] = 1;
    for(int i = 2; i < 100000; i++)
    {
        if(!tag[i]) p[cnt++] = i;
        for(int j = 0; j < cnt && p[j] * i < 100000; j++)
        {
            tag[i * p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}
void get(long long x)
{
    for(int i = 0; i < cnt && x >= (long long)p[i] * (long long)p[i]; i++)
        if(x % p[i] == 0)
        {
            s.insert(p[i]);
            while(x % p[i] == 0) x /= p[i];
        }
    if(x != 1)
        s.insert(x);
}
void get2(long long x)
{
    long long tx = x;
    for(int i = 0; i < cnt && x >= (long long)p[i] * (long long)p[i]; i++)
        if(x % p[i] == 0)
        {
            long long tmp = (long long)p[i];
            while(x % tmp == 0) x /= tmp;
            g[tx - l + 1].push_back(id[tmp]);
        }
    if(x != 1)
        g[tx - l + 1].push_back(id[x]);
}
int path(int u)
{
    int sz = g[u].size();
    for(int i = 0; i < sz; i++)
    {
        int v = g[u][i];

        if(!mark[v] && !used[v])
        {
            mark[v] = 1;
            if(cy[v] == -1 || path(cy[v]))
            {
                cx[u] = v;
                cy[v] = u;
                return 1;
            }
        }
    }
    return 0;
}

bool ok(int t)
{
    memset(cy, -1, sizeof(cy));
    for(int i = t + 1; i <= up; i++)
    {
        memset(mark, 0, sizeof(mark));
        if(!path(i)) return false;
    }
    return true;
}
void fix()
{
    for(int i = 1; i <= up; i++)
    {
        int sz = g[i].size();
        for(int j = 0; j < sz; j++)
        {
            int v = g[i][j];
            if(used[v]) continue;
            cx[i] = v;
            used[v] = 1;
            if(!ok(i)) used[v] = 0;
            else break;
        }
        used[cx[i]] = 1;
    }
}
void out(long long a )
{
    if(a >= 10) out(a / 10);
    putchar('0' + a % 10);
}
int main()
{
    getprime();

    while(scanf("%lld%lld", &l, &r) != EOF)
    {
        if(l == 0 && r == 0) break;
        s.clear();
        id.clear();
        up = r - l + 1;
        for(int i = 1; i <= up; i++) g[i].clear();
        memset(ans, -1, sizeof(ans));
        memset(used, 0, sizeof(used));
        m = 0;
        for(long long i = l; i <= r; i++)
            get(i);
        for(set<long long>::iterator it = s.begin(); it != s.end(); it++)
        {
            a[m++] = *it;
            id[a[m - 1]] = m;
        }
        for(long long i = l; i <= r; i++)
            get2(i);
        fix();
        for(int i = 1; i < up; i++)
        {
            //printf("%lld ", a[cx[i] - 1]);
            out(a[cx[i] - 1]);
            putchar(' ');
        }
        out(a[cx[up] - 1]);
        putchar('\n');
        //printf("%lld\n", a[cx[up] - 1]);
    }
    return 0;
}


 

 

posted on 2013-10-06 03:35  you Richer  阅读(198)  评论(0编辑  收藏  举报