LightOJ - 1370(欧拉公式)
也就是欧拉公式板子题吧
#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
不过做这道题之前先来道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);
}
}
好了已经会套用板子了,然后进行一些细节上的建图优化就可以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);
}
}