数论基础题 LightOJ - 1370(欧拉公式) 也就是欧拉公式板子题吧 第二道题就有点儿恶心了。。。LightOJ - 1356。题意:给出一系列数,求出最大的子集使得子集中每个元素两两相除(大的除以小的)得到的结果不能是素数。 解题思路:建图求得最大的独立集(一些好的关于二分图的博客如下) 不过做这道题之前先来道Hdu 2389(作为二分图匹配HK算法的板子题,原理以后弄懂了再讲,当初离散还是学得太浅了) 直接看这道题,自己写了HK算法,然后交了一发 好了已经会套用板子了,然后进行一些细节上的建图优化就可以A了(毒瘤题) LightOJ - 1341(线性筛优化+唯一分解定理+质因数分解)

也就是欧拉公式板子题吧

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 1e6 + 10;

ll phi[MAXN + 1];
void euler(int n) {
	for(int i = 2; i <= n; ++i)	phi[i] = i;
	for(int i = 2; i <= n; ++i) {
		if(phi[i] == i) {
			for(int j = i; j <= n; j+=i) {
				phi[j] = phi[j] / i * (i - 1);
			}
		}
	}
}
int main () {
	euler(MAXN);
	int T;
	scanf("%d", &T);
	int n;
	int i = 0;
	while(T--) {
		scanf("%d", &n);
		ll ans = 0;
		while(n--) {
			ll x;
			scanf("%lld", &x);
			ll temp = x + 1;
			while(phi[temp] < x) {
				temp++;
			}
			ans += temp;
		}
		printf("Case %d: %lld Xukha
", ++i, ans);
	}
}

第二道题就有点儿恶心了。。。LightOJ - 1356。题意:给出一系列数,求出最大的子集使得子集中每个元素两两相除(大的除以小的)得到的结果不能是素数。

解题思路:建图求得最大的独立集(一些好的关于二分图的博客如下)

https://www.cnblogs.com/lucianosimon/p/9415848.html

https://blog.csdn.net/Wall_F/article/details/8248373

https://www.cnblogs.com/lucianosimon/p/9415848.html

https://blog.csdn.net/ErrorNam/article/details/82976377?utm_medium=distribute.pc_relevant.none-task-blog-searchFromBaidu-6.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-searchFromBaidu-6.control

不过做这道题之前先来道Hdu 2389(作为二分图匹配HK算法的板子题,原理以后弄懂了再讲,当初离散还是学得太浅了)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 3000 + 10;
const ll MAXM = MAXN * MAXN;
const ll INF = 0x3f3f3f3f;
struct Edge
{
	int v;
	int nxt;
}edge[MAXM];
struct node
{
	double x, y;
	double v;
}a[MAXN], b[MAXN];
ll nx, ny, cnt, t, dis;
ll first[MAXN], xlink[MAXN], ylink[MAXN];
ll dx[MAXN], dy[MAXN];
ll vis[MAXN];

void init() {
	cnt = 0;
	memset(first, -1, sizeof first);
	memset(xlink, -1, sizeof xlink);
	memset(ylink, -1, sizeof ylink);
}

void addEdge(ll u, ll v) {
	edge[cnt].v = v;
	edge[cnt].nxt = first[u];
	first[u] = cnt++;
}

double dist(const node a, const node b) {
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

int bfs() {
	queue<int> q;
	dis = INF;
	memset(dx, -1, sizeof dx);
	memset(dy, -1, sizeof dy);
	for(int i = 0; i < nx; ++i) {
		if(xlink[i] == -1) {
			q.push(i);
			dx[i] = 0;
		}
	}
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		if(dx[u] > dis) {
			break;
		}
		for(int e = first[u]; e != -1; e = edge[e].nxt) {
			int v = edge[e].v;
			if(dy[v] == -1) {
				dy[v] = dx[u] + 1;
				if(ylink[v] == -1) {
					dis = dy[v];
				} else {
					dx[ylink[v]] = dy[v] + 1;
					q.push(ylink[v]);
				}
			}
		}
	}
	return dis != INF;
}

int find(int u) {
	for(int e = first[u]; e != -1; e = edge[e].nxt) {
		int v = edge[e].v;
		if(!vis[v] && dy[v] == dx[u] + 1) {
			vis[v] = 1;
			if(ylink[v] != -1 && dy[v] == dis) {
				continue;
			}
			if(ylink[v] == -1 || find(ylink[v])) {
				xlink[u] = v;
				ylink[v] = u;
				return 1;
			}
		}
	}
	return 0;
}
int MaxMatch() {
	int ans = 0;
	while(bfs()) {
		memset(vis, 0, sizeof vis);
		for(int i = 0; i < nx; ++i) {
			if(xlink[i] == -1) {
				ans += find(i);
			}
		}
	}
	return ans;
}

int main () {
	int T;
	int times = 0;
	scanf("%d", &T);
	while(T--) {
		printf("Scenario #%d:
", ++times);
		init();
		int Time;
		scanf("%d", &Time);
		scanf("%d", &nx);
		for(int i = 0; i < nx; ++i) {
			scanf("%lf%lf%lf", &a[i].x, &a[i].y, &a[i].v);
		}
		scanf("%d", &ny);
		for(int i = 0; i < ny; ++i) {
			scanf("%lf%lf", &b[i].x, &b[i].y);
		}
		for(int i = 0; i < nx; ++i) {
			for(int j = 0; j < ny; ++j) {
				double limit = a[i].v * Time;
				double s = dist(a[i], b[j]);
				if(s <= limit) {
					addEdge(i, j);
				}
			}
		}
		int ans = MaxMatch();
		printf("%d

", ans);
	}
}

直接看这道题,自己写了HK算法,然后交了一发

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 40000 + 10;
const ll MAXM = 40000;
const ll INF = 0x3f3f3f3f;
int prime[MAXN];
bool isPrime[MAXN];
struct Edge
{
	int v;
	int nxt;
}edge[MAXM];
struct node
{
	double x, y;
	double v;
}a[MAXN], b[MAXN];
ll nx, ny, cnt, dis;
ll first[MAXN], xlink[MAXN], ylink[MAXN];
ll dx[MAXN], dy[MAXN];
ll vis[MAXN];
std::vector<int> v1;
std::vector<int> v2;

int v[MAXN];
void init() {
	memset(edge, 0, sizeof edge);
	memset(a, 0, sizeof a);
	memset(b, 0, sizeof b);
	cnt = 0;
	memset(first, -1, sizeof first);
	memset(xlink, -1, sizeof xlink);
	memset(ylink, -1, sizeof ylink);
	v1.clear();
	v2.clear();
}
void firstinit() {
	memset(prime, 0, sizeof prime);
	memset(isPrime, 0, sizeof isPrime);
	memset(v, 0, sizeof v);
	int m = 0;
	for(int i = 2; i <= MAXN; ++i) {
		if(v[i] == 0) {
			v[i] = i;
			prime[++m] = i;
			isPrime[i] = 1;
		}
		for(int j = 1; j <= m; ++j) {
			if(prime[j] > v[i] || prime[j] > MAXN / i) {
				break;
			}
			v[i * prime[j]] = prime[j];
		}
	}
}
void addEdge(ll u, ll v) {
	edge[cnt].v = v;
	edge[cnt].nxt = first[u];
	first[u] = cnt++;
}


int bfs() {
	queue<int> q;
	dis = INF;
	memset(dx, -1, sizeof dx);
	memset(dy, -1, sizeof dy);
	for(int i = 0; i < nx; ++i) {
		if(xlink[i] == -1) {
			q.push(i);
			dx[i] = 0;
		}
	}
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		if(dx[u] > dis) {
			break;
		}
		for(int e = first[u]; e != -1; e = edge[e].nxt) {
			int v = edge[e].v;
			if(dy[v] == -1) {
				dy[v] = dx[u] + 1;
				if(ylink[v] == -1) {
					dis = dy[v];
				} else {
					dx[ylink[v]] = dy[v] + 1;
					q.push(ylink[v]);
				}
			}
		}
	}
	return dis != INF;
}

int find(int u) {
	for(int e = first[u]; e != -1; e = edge[e].nxt) {
		int v = edge[e].v;
		if(!vis[v] && dy[v] == dx[u] + 1) {
			vis[v] = 1;
			if(ylink[v] != -1 && dy[v] == dis) {
				continue;
			}
			if(ylink[v] == -1 || find(ylink[v])) {
				xlink[u] = v;
				ylink[v] = u;
				return 1;
			}
		}
	}
	return 0;
}
int MaxMatch() {
	int ans = 0;
	while(bfs()) {
		memset(vis, 0, sizeof vis);
		for(int i = 0; i < nx; ++i) {
			if(xlink[i] == -1) {
				ans += find(i);
			}
		}
	}
	return ans;
}

int divide(int n) {
	int m = 0;
	for(int i = 2; i <= sqrt(n); ++i) {
		if(n % i == 0) {
			//m++;
			while(n % i == 0) {
				n /= i;
				m++;
			}
		}
	}
	if(n > 1) {
		m = 1;
	}
	return m;
}

int main () {
	firstinit();
	int T;
	scanf("%d", &T);
	int t = 0;
	while(T--) {
		init();
		int N;
		scanf("%d", &N);
		for(int i = 0; i < N; ++i) {
			int temp;
			scanf("%d", &temp);
			if(divide(temp) & 1) {
				v1.push_back(temp);
			} else {
				v2.push_back(temp);
			}
		}

		nx = v1.size();
		ny = v2.size();

		for(int i = 0; i < v1.size(); ++i) {
			for(int j = 0; j < v2.size(); ++j) {
				if(max(v1[i], v2[j]) % min(v1[i], v2[j]) == 0 && isPrime[max(v1[i], v2[j]) / min(v1[i], v2[j])] == 1) {
					addEdge(i, j);
				} 
			}
		}
		int ans = MaxMatch();
		ans = N - ans;
		printf("Case %d: %d
", ++t, ans);
	}
}

数论基础题
LightOJ - 1370(欧拉公式)
也就是欧拉公式板子题吧
第二道题就有点儿恶心了。。。LightOJ - 1356。题意:给出一系列数,求出最大的子集使得子集中每个元素两两相除(大的除以小的)得到的结果不能是素数。
解题思路:建图求得最大的独立集(一些好的关于二分图的博客如下)
不过做这道题之前先来道Hdu 2389(作为二分图匹配HK算法的板子题,原理以后弄懂了再讲,当初离散还是学得太浅了)
直接看这道题,自己写了HK算法,然后交了一发
好了已经会套用板子了,然后进行一些细节上的建图优化就可以A了(毒瘤题)
LightOJ - 1341(线性筛优化+唯一分解定理+质因数分解)

好了已经会套用板子了,然后进行一些细节上的建图优化就可以A了(毒瘤题)


#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int N=5e5+10;
const int INF=0x3f3f3f3f;
int a[N];
vector<int> G[40005];//大了会超空间
int n;
 
 
bool prime[N];//prime[i]表示i是不是质数 
int p[N], tot;//p[N]用来存质数,tot记录有多少个质数 
void init(){//预处理所有的质数 
    for(int i = 2; i < N; i ++) prime[i] = true;//初始化为质数 
    for(int i = 2; i < N; i++){
        if(prime[i]) p[tot ++] = i;//把质数存起来 
        for(int j = 0; j < tot && i * p[j] < N; j++){
            prime[i * p[j]] = false;
            if(i % p[j] == 0) break;//保证每个合数被它最小的质因数筛去 
        }
    }    
}
 
 
int pos[N];
int B[N];
void solve(){
	for(int i=1;i<=n;++i){
		int cnt=0,cnt2=0;//第一个记录质因子个数,第二个是总共因子的个数 
		int temp=a[i];//先存下来原来的数 
		for(int j=0;p[j]*p[j]<=temp;j++){
			if(temp%p[j]==0){//找到质因子 
				B[cnt++]=p[j];
				while(temp%p[j]==0){
					temp/=p[j];
					cnt2++;
				}
			}
		}
		if(temp>1){//最后一个特判 
			B[cnt++]=temp;
			cnt2++;
		} 
		for(int j=0;j<cnt;++j){//对每一个质因子考虑 
			temp=pos[a[i]/B[j]];
			if(temp<=i&&temp!=-1){//如果该数除去质因子后的数在集合里面,并且在当前数字的前面(排序过了) 
				if(cnt2%2) G[i].push_back(temp);//按照因子个数的奇偶建图 
				else G[temp].push_back(i);
			}
		}
	}
}
 
//HK算法求最大匹配 
int cx[N],cy[N],visited[N],dy[N],dx[N];
int dis;
int bfs()
{
    queue<int> Q;
    dis = INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=1; i<=n; i++)
    {
        if(cx[i] == -1)
        {
            Q.push(i);
            dx[i] = 0;
        }
    }
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        if(dx[u] > dis) break;
        for(int v=0; v<G[u].size(); v++)
        {
            int i = G[u][v];
            if(dy[i] == -1)
            {
                dy[i] = dx[u] + 1;
                if(cy[i] == -1) dis = dy[i];
                else
                {
                    dx[cy[i]] = dy[i] + 1;
                    Q.push(cy[i]);
                }
            }
 
        }
    }
    return dis != INF;
}
 
int find(int u)
{
    for(int v=0; v<G[u].size(); v++)
    {
        int i = G[u][v];
        if(!visited[i] && dy[i] == dx[u] + 1)
        {
            visited[i] = 1;
            if(cy[i] != -1 && dis == dy[i]) continue;
            if(cy[i] == -1 || find(cy[i]))
            {
                cy[i] = u;
                cx[u] = i;
                return 1;
            }
        }
    }
    return 0;
}
int match(){
	int ans=0;
	memset(cx,-1,sizeof(cx));
	memset(cy,-1,sizeof(cy));
	while(bfs()){
		memset(visited,0,sizeof(visited));
		for(int i=1;i<=n;++i)
			if(cx[i]==-1&&find(i))
				ans++;
	}
	return ans;
}
 
 
int main(){
	int T;
	scanf("%d",&T);
	init(); 
	for(int kcase=1;kcase<=T;kcase++){
		for(int i=0;i<40005;++i)
			G[i].clear();
		memset(pos,-1,sizeof(pos));//初始化 
		scanf("%d",&n);
		for(int i=1;i<=n;++i)
			scanf("%d",&a[i]);
		sort(a+1,a+1+n);
		for(int i=1;i<=n;++i)
			pos[a[i]]=i;//排序编号 
		solve();//建图 
		printf("Case %d: %d
",kcase,n-match());		
	}
	return 0;
}

LightOJ - 1341(线性筛优化+唯一分解定理+质因数分解)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 1e6 + 10;
ll v[MAXN], prime[MAXN];
ll m;
void primes(int n) {
	memset(v, 0, sizeof v);
	m = 0;
	for(int i = 2; i <= n; ++i) {
		if(v[i] == 0) {
			v[i] = i;
			prime[++m] = i;
		}
		for(int j = 1; j <= m; ++j) {
			if(prime[j] > v[i] || prime[j] > n / i) {
				break;
			}
			v[i * prime[j]] = prime[j];
		}
	}
}

ll divide(ll n) {
	ll temp = 0;
	ll s = 1;
	for(ll i = 1; prime[i] < n && i <= m; ++i) {
		temp = 0;
		if(n % prime[i] == 0) {
			//m++;
			while(n % prime[i] == 0) {
				n /= prime[i];
				temp++;
			}
		}
		s *= (temp + 1);
	}
	if(n > 1) {
		s *= 2;
	}
	return s;
}

int main () {
	primes(MAXN);
	int T;
	scanf("%d", &T);
	int t = 0;
	while(T--) {
		ll a, b;
		scanf("%lld%lld", &a, &b);
		// cin >> a >> b;
		ll ans = 0;
		if(b * b > a) {
			ans = 0;
		} else {
			ll cnt = 0;
			for(ll i = 1; i < b; ++i) {
				if(a % i == 0) {
					cnt++;
				} 
			}
			ans = divide(a) / 2 - cnt;
		}
		printf("Case %d: %lld
", ++t, ans);
	}
	
}