UVALive 6198 A Terribly Grimm Problem 二分匹配 求字典序最小解

题目链接:点击打开链接

题意:

给定一个区间[l,r]

每个数都选择他的其中一个因子。

使得任意两个数选择的因子各不相同,且字典序最小。

思路:

先对每个数分解质因数。

然后从l开始枚举,让i选择最小的因子,判断 [i+1,r]是否有可行解,若有则让i选择这个因子。

如此枚举下去即可

==复杂度不能直视

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include <cmath>
#include <map>
#include<vector>
template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
using namespace std;
typedef long long ll;
const int N = 1000000;
ll prime[9592],primenum;//有primenum个素数 math.h
void PRIME(ll Max_Prime){
    primenum=0;
    prime[primenum++]=2;
    for(ll i=3;i<=Max_Prime;i+=2)
    for(ll j=0;j<primenum;j++)
        if(i%prime[j]==0)break;
        else if(prime[j]>sqrt((double)i) || j==primenum-1)
        {
            prime[primenum++]=i;
            break;
        }
}
void get_prime(ll x, vector<ll> &G){
 //    cout<<"i:"<<x<<"{";
    for(ll i = 0; prime[i]*prime[i]<=x; i++)
        if(x%prime[i] == 0){
        G.push_back(prime[i]);
        while(x%prime[i]==0)x/=prime[i];
        }
    if(x!=1)
        G.push_back(x);

//for(int i = 0; i < G.size(); i++)cout<<G[i]<<" ";cout<<endl;
}
ll l, r;
vector<ll>G[N];
void input(){
    for(ll i = l; i <= r; i++)
        get_prime(i, G[i-l]);
}

map<ll,ll>lef, rig;//lef[v]表示Y集的点v 当前连接的点 , pn为x点集的点数
map<ll,bool> T, must;     //T[u] 表示Y集 u 是否已连接X集

bool match(ll x){ // x和Y集 匹配 返回x点是否匹配成功
    for(int i=0; i<G[x-l].size(); i++)
    {
        ll v = G[x-l][i];
        if(!T[v] && !must[v])
        {
            T[v] = 1;
            if((int)lef.count(v)==0 ||match(lef[v]))   //match(lef[v]) : 原本连接v的X集点 lef[v] 能不能和别人连,如果能 则v这个点就空出来和x连
            {
                lef[v] = x;
                return true;
            }
        }
    }
    return false;
}
bool find(ll x){
    lef.clear();
    for(x++; x <= r; x++)
    {
        T.clear();
        if(!match(x))return false;
    }
    return true;
}
void solve(){
    rig.clear();
    must.clear();
    for(ll i = l; i<= r; i++)//X集匹配,X集点标号从 1-pn 匹配边是G[左点].size()
    {
        for(int j = 0; j < G[i-l].size(); j++)
        {
            ll v = G[i-l][j];
            if(must[v])continue;
            rig[i] = v;
            must[v] = 1;
            if(!find( i ))must[v] = 0;
            else break;
        }
        must[rig[i]] = 1;
    }
}

int main(){
    PRIME(100000);
    while(cin>>l>>r, l+r){
        input();
        solve();
        for(ll i = l; i <= r; i++)
            printf("%lld%c", rig[i], i==r?'\n':' ');
        for(ll i = l; i <= r; i++)
            G[i-l].clear();
    }
    return 0;
}
时间: 2024-08-07 04:18:06

UVALive 6198 A Terribly Grimm Problem 二分匹配 求字典序最小解的相关文章

HDU 3289 Cat VS Dog (二分匹配 求 最大独立集)

题意:每个人有喜欢的猫和不喜欢的狗.留下他喜欢的猫他就高心,否则不高心.问最后最多有几个人高心. 思路:二分图求最大匹配 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdlib> 6 #include<string> 7 #include<cmath> 8 #include<

poj 3041Asteroids 二分匹配求最小点覆盖模板题

//最大匹配=最小覆盖 //这题是求最小覆盖点的模板题 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 510; int line[maxn][maxn]; int match[maxn]; int vis[maxn]; int N , K; int find(int start) { for(int i = 1;i <=  N;

UVALive 6525 Attacking rooks 二分匹配 经典题

题目链接:option=com_onlinejudge&Itemid=8&page=show_problem&problem=4536">点击打开链接 题意: 给定n*n的棋盘, 能够在'.'上摆 象棋中的车(X是墙壁) 使得随意两个车都不能互相攻击到 问:最多能摆多少个车. 思路: 二分匹配 1.若没有X.那么做法就是 X点集为行,Y点集为列,对于图上的每一个点所在的行和列(x,y) 建一条边 x->y 2.有了X,那么对于每一个点所在的上方能接触到的X必须

HDU 3861 The King’s Problem (强连通+二分匹配)

题目地址:HDU 3861 这题虽然是两个算法结合起来的.但是感觉挺没意思的..结合的一点也不自然,,硬生生的揉在了一块...(出题者不要喷我QAQ.) 不过这题让我发现了我的二分匹配已经好长时间没用过了..都快忘了..正好在省赛之前又复习了一下. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm>

HDU 3861 The King’s Problem 连通分量+二分匹配

题意:n个城市,m条有向边, 现在要把这个图分成块,对于块的定义:1,所有能够互通的点一定在一个块内.2,一个点可以到达另一个点,所经过的点只能是这个块内的.问做少要分多少个块? 想法:显然tarjan先缩点,然后可以想到,要想百分之一百满足第2个条件,那么每一个块最多只能有所点后的两个点,所以对所得的缩点进行二分匹配,然后求得最大独立集=col-(最大匹配数) #include<iostream> #include<cstdio> #include<cstring>

hdu 4185 Oil Skimming(二分匹配)

Oil Skimming Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 883    Accepted Submission(s): 374 Problem Description Thanks to a certain "green" resources company, there is a new profitable

hdu 5093 Battle ships 最大二分匹配

Battle ships Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 589    Accepted Submission(s): 233 Problem Description Dear contestant, now you are an excellent navy commander, who is responsible

hdoj 2063 过山车 【二分匹配之匈牙利算法】

过山车 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11520    Accepted Submission(s): 5072 Problem Description RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了.可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做pa

hdu-----(1179)Ollivanders: Makers of Fine Wands since 382 BC.(二分匹配)

Ollivanders: Makers of Fine Wands since 382 BC. Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 935    Accepted Submission(s): 523 Problem Description In Diagon Alley ,there is only one Wand-se