题目描述
分析
因为gcd有一个特性,区间的公约数等于区间分割后的公约数.所以我门可以预处理一张大的ST表也就是可以用RMQ查询.
然后我们对每一个左端点枚举求出不同gcd的计数(开一个map),暴力的方法就是再枚举右端点。可是由于n太大了,这没法暴力。由于gcd随着区间长度的增长肯定是递减的,所以我们可以二分的来预处理.(
code
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
#include <vector>
#include <queue>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int,int> Pair;
typedef long long LL;
const int MAX_V = 30;
const int MAX_E = 1e4+10;
const int maxn = 1e5+10;
//二分图匹配模板
int V;
std::vector<int> G[MAX_V];
bool used[MAX_V];
int match[MAX_V];
bool dfs(int u){
used[u] = true;
for(int i=0 ; i<G[u].size() ; ++i){
int v = G[u][i];int w = match[v];
if(w<0 || !used[w] && dfs(w)){
match[u] = v;match[v] = u;
return true;
}
}
return false;
}
int bipartite_match(){
int res = 0;
memset(match,-1,sizeof(match));
for(int i = 1 ; i<=V ; ++i){
if(match[i]<0){
memset(used,false,sizeof(used));
if(dfs(i))res++;
}
}
return res;
}
void add_edge(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
int p[20];
int judge[10][10];//是否两个冲突
//建图
void build_graph(int n){
V = n*2;
for(int i=1 ; i<=n ; ++i){
int j = (i == n? 1 :i+1);
for(int k = 1; k <=n ; ++k){
if(judge[k][p[i]] || judge[k][p[j]])continue;
add_edge(i,n+k);
}
}
}
int main(int argc, char const *argv[]) {
int n,m;
while (scanf("%d%d", &n,&m)!=EOF) {
for(int i=0 ; i<=n ; ++i)p[i] = i;
memset(judge,0,sizeof(judge));
for(int i=0 ; i<m ; ++i){
int x,y;
scanf("%d%d",&x,&y );
judge[x][y] =1;
}
if(n == 0){
std::cout << 0 << '\n';
continue;
}
int ans = 0;
do{
for(int i=0 ; i<=20 ; ++i)G[i].clear();
build_graph(n);
ans = max(bipartite_match(),ans);
}while (next_permutation(p+2,p+n+1));//园排列,固定一个端点;
printf("%d\n",n-ans );
}
return 0;
}