ID
Origin
Title
  111 / 423 Problem A LightOJ 1370 Bi-shoe and Phi-shoe
  21 / 74 Problem B LightOJ 1356 Prime Independence
  61 / 332 Problem C LightOJ 1341 Aladdin and the Flying Carpet
  54 / 82 Problem D LightOJ 1336 Sigma Function
  66 / 181 Problem E LightOJ 1282 Leading and Trailing
  65 / 216 Problem F LightOJ 1259 Goldbach`s Conjecture
  65 / 110 Problem G LightOJ 1245 Harmonic Number (II)
  48 / 172 Problem H LightOJ 1236 Pairs Forming LCM
  43 / 73 Problem I LightOJ 1234 Harmonic Number
  38 / 160 Problem J LightOJ 1220 Mysterious Bacteria
  46 / 98 Problem K LightOJ 1214 Large Division
  35 / 62 Problem L LightOJ 1213 Fantasy of a Summation
  41 / 137 Problem M LightOJ 1197 Help Hanzo
  45 / 100 Problem N LightOJ 1138 Trailing Zeroes (III)
  37 / 48 Problem O UVA 11426 GCD - Extreme (II)
  13 / 65 Problem P UVA 11754 Code Feat
  9 / 26 Problem Q UVA 11916 Emoogle Grid
  36 / 86 Problem R POJ 1061 青蛙的约会
  24 / 63 Problem S POJ 2115 C Looooops
  13 / 35 Problem T POJ 2116 Death to Binary?
  61 / 122 Problem U HDU 2161 Primes
  32 / 87 Problem V UVA 11827 Maximum GCD
  25 / 98 Problem W UVA 10200 Prime Time
  20 / 154 Problem X SGU 106 The equation
  34 / 51 Problem Y POJ 2478 Farey Sequence
  23 / 63 Problem Z UVA 11752 The Super Powers
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


111 / 423 Problem A LightOJ 1370 Bi-shoe and Phi-shoe

d.给出n个数a1,a2,...,an,对每个数ai分别找到一个相应的数pi,使其欧拉函数值Φ(pi)>=ai,求p1+p2+...+pn的最小值。

s.不知道为什么pi要选大于ai的第一个素数。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;

const int MAXN=1000100;

bool isPrime[MAXN];

void sieve(int n){
    memset(isPrime,true,sizeof(isPrime));
    isPrime[0]=isPrime[1]=false;
    int i,j,k;
    k=sqrt(n);
    for(i=2;i<=k;++i){
        if(isPrime[i]==true){
            for(j=i+i;j<=n;j=j+i){
                isPrime[j]=false;
            }
        }
    }
}

int main(){

    sieve(MAXN-1);

    int T;
    int n;
    int t;
    int i;
    int j;
    long long sum;
    int ca=0;

    scanf("%d",&T);

    while(T--){
        scanf("%d",&n);
        sum=0;
        for(i=0;i<n;++i){
            scanf("%d",&t);
            for(j=t+1;j<MAXN;++j){
                if(isPrime[j]==true){
                    break;
                }
            }
            sum+=j;
        }
        printf("Case %d: %lld Xukha\n",++ca,sum);
    }

    return 0;
}
View Code

 

21 / 74 Problem B LightOJ 1356 Prime Independence

题意:
找出一些数字的最大质独立集,就是集合能的所有数互相之间不会出现 a[i]==t*a[j] (t是质数) 的情况。
思路:
首先想最大独立集对于一般图是NP问题,通常只有求二分图最大独立集,然后就是如何把这些数字分为二分图。
能够想到如果一个数字等于另一个数字乘以一个质数,那么这两个数字的质因子分解应该只有这一个质数的差别。也就是只会多一个质数,数字上限只有500000,完全可以看一个数组储存某个数字是否存在,然后对每个数字分解质因子,找到他对于每个质因子能够找到的那个数,存在则加边,然后就把质因子总个数(可重复的)是奇数与偶数的分成两边并且把只有一个质因子差别的连通,然后二分图匹配求最大独立集即可。

即二分图左边为质因子总数为奇数的,右边为质因子总数偶数的。
关于二分图匹配因为数量较大所以用匈牙利会tle,要用Hopcroft-Carp:

c.根据这个思路写了下,用的匈牙利O(VE),没超时。不过Hopcroft-Carp这个会快1s左右。

/*
//顶点编号从1开始的
用STL中的vector建立邻接表实现匈牙利算法
效率比较高
处理点比较多的效率很高。1500的点都没有问题
*/
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<math.h>
using namespace std;

const int MAXN=40000+10;//这个值要超过两边个数的较大者,因为有linker
int linker[MAXN];
bool used[MAXN];
vector<int>G[MAXN];
int uN;
bool dfs(int u)
{
    int sz=G[u].size();
    for(int i=0; i<sz; i++)
    {
        if(!used[G[u][i]])
        {
            used[G[u][i]]=true;
            if(linker[G[u][i]]==-1||dfs(linker[G[u][i]]))
            {
                linker[G[u][i]]=u;
                return true;
            }
        }
    }
    return false;
}

int hungary()
{
    int u;
    int res=0;
    memset(linker,-1,sizeof(linker));
    for(u=0; u<uN; u++)
    {
        memset(used,false,sizeof(used));
        if(dfs(u)) res++;
    }
    return res;
}

const int MAXN2=500000+10;

bool exist[MAXN2];//标记数是否存在
int a[MAXN];//原来的数
int myHash[MAXN2];//离散化

int factors[MAXN2][2];//[0]存质因子,[1]存个数
int factCnt;//不同的质因子总个数
int factCnt2;//包含相同的质因子的总个数

void getFactors(int n){
    int i,k;
    factCnt=0;
    factCnt2=0;
    for(i=2,k=sqrt(n);i<=k;++i){
        if(n%i==0){
            factors[factCnt][0]=i;
            factors[factCnt][1]=1;
            ++factCnt2;
            n=n/i;
            while(n%i==0){
                ++factors[factCnt][1];
                ++factCnt2;
                n=n/i;
            }
            ++factCnt;
            k=sqrt(n);//循环条件不直接写i<=sqrt(n);是因为这样可以避免重复开跟方
        }
    }
    if(n>1){
        factors[factCnt][0]=n;
        factors[factCnt][1]=1;
        ++factCnt;
        ++factCnt2;
    }
}

int main(){
    int T;
    int N;
    int i;
    int j;
    int tmp;
    int ans;
    int ca=0;

    scanf("%d",&T);

    while(T--){
        scanf("%d",&N);
        uN=N;//左边集合个数
        for(i=0;i<uN;++i){//记得要清空
            G[i].clear();
        }

        memset(exist,false,sizeof(exist));
        for(i=0;i<N;++i){
            scanf("%d",&a[i]);
            exist[a[i]]=true;
            myHash[a[i]]=i;//离散化,二分图N个点就可以了
        }

        for(i=0;i<N;++i){
            getFactors(a[i]);//获取质因子
            for(j=0;j<factCnt;++j){//枚举质因子
                tmp=a[i]/factors[j][0];
                if(exist[tmp]==true){//tmp存在
                    if(factCnt2&1){//第i个数质因数个数为奇数,第i个数作为左边的点插入一条由左指向右的有向边
                        G[i].push_back(myHash[tmp]);
                    }
                    else{
                        G[myHash[tmp]].push_back(i);
                    }
                }
            }
        }
        ans=hungary();
        printf("Case %d: %d\n",++ca,N-ans);
    }

    return 0;
}
View Code

c2.Hopcroft-Carp,这个比较快,O(squt(n)*E)

/*
//顶点编号从0开始的
二分图匹配(Hopcroft-Karp算法)
复杂度O(squt(n)*E)
邻接表存图,vector实现
vector先初始化,然后加入边
uN为左端的顶点数,使用前赋值(点编号0开始)
*/
#include<iostream>
#include<stdio.h>
#include<vector>
#include<queue>
#include<string.h>
#include<math.h>
using namespace std;

const int MAXN=40000+10;
const int INF=0x3f3f3f3f;
vector<int>G[MAXN];
int uN;
int Mx[MAXN],My[MAXN];
int dx[MAXN],dy[MAXN];
int dis;
bool used[MAXN];
bool SearchP(){
    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<uN;i++)
        if(Mx[i]==-1){
            Q.push(i);
            dx[i]=0;
        }
    while(!Q.empty()){
        int u=Q.front();
        Q.pop();
        if(dx[u]>dis)break;
        int sz=G[u].size();
        for(int i=0;i<sz;i++){
            int v=G[u][i];
            if(dy[v]==-1){
                dy[v]=dx[u]+1;
                if(My[v]==-1)dis=dy[v];
                else{
                    dx[My[v]]=dy[v]+1;
                    Q.push(My[v]);
                }
            }
        }
    }
    return dis!=INF;
}
bool DFS(int u){
    int sz=G[u].size();
    for(int i=0;i<sz;i++){
        int v=G[u][i];
        if(!used[v]&&dy[v]==dx[u]+1){
            used[v]=true;
            if(My[v]!=-1&&dy[v]==dis)continue;
            if(My[v]==-1||DFS(My[v])){
                My[v]=u;
                Mx[u]=v;
                return true;
            }
        }
    }
    return false;
}
int MaxMatch(){
    int res=0;
    memset(Mx,-1,sizeof(Mx));
    memset(My,-1,sizeof(My));
    while(SearchP()){
        memset(used,false,sizeof(used));
        for(int i=0;i<uN;i++)
            if(Mx[i]==-1&&DFS(i))
                res++;
    }
    return res;
}

const int MAXN2=500000+10;

bool exist[MAXN2];//标记数是否存在
int a[MAXN];//原来的数
int myHash[MAXN2];//离散化

int factors[MAXN2][2];//[0]存质因子,[1]存个数
int factCnt;//不同的质因子总个数
int factCnt2;//包含相同的质因子的总个数

void getFactors(int n){
    int i,k;
    factCnt=0;
    factCnt2=0;
    for(i=2,k=sqrt(n);i<=k;++i){
        if(n%i==0){
            factors[factCnt][0]=i;
            factors[factCnt][1]=1;
            ++factCnt2;
            n=n/i;
            while(n%i==0){
                ++factors[factCnt][1];
                ++factCnt2;
                n=n/i;
            }
            ++factCnt;
            k=sqrt(n);//循环条件不直接写i<=sqrt(n);是因为这样可以避免重复开跟方
        }
    }
    if(n>1){
        factors[factCnt][0]=n;
        factors[factCnt][1]=1;
        ++factCnt;
        ++factCnt2;
    }
}

int main(){
    int T;
    int N;
    int i;
    int j;
    int tmp;
    int ans;
    int ca=0;

    scanf("%d",&T);

    while(T--){
        scanf("%d",&N);
        uN=N;//左边集合个数
        for(i=0;i<uN;++i){//记得要清空
            G[i].clear();
        }

        memset(exist,false,sizeof(exist));
        for(i=0;i<N;++i){
            scanf("%d",&a[i]);
            exist[a[i]]=true;
            myHash[a[i]]=i;//离散化,二分图N个点就可以了
        }

        for(i=0;i<N;++i){
            getFactors(a[i]);//获取质因子
            for(j=0;j<factCnt;++j){//枚举质因子
                tmp=a[i]/factors[j][0];
                if(exist[tmp]==true){//tmp存在
                    if(factCnt2&1){//第i个数质因数个数为奇数,第i个数作为左边的点插入一条由左指向右的有向边
                        G[i].push_back(myHash[tmp]);
                    }
                    else{
                        G[myHash[tmp]].push_back(i);
                    }
                }
            }
        }
        ans=MaxMatch();
        printf("Case %d: %d\n",++ca,N-ans);
    }

    return 0;
}
View Code

 

61 / 332 Problem C LightOJ 1341 Aladdin and the Flying Carpet

题意:给个矩形的面积a,和矩形的最小边长b,问有多少种矩形的方案(不能是正方形)

分析:a可以写成x,y,因为不能是正方形,所以设x<y,那么x<sqrt(a),y>sqrt(a)

        所以找到所有小于sqrt(a)的因子,看有几个大于等于b的就是方案数

        因子可以由数的唯一分解定理,求得

具体 : 先筛一遍1e6以内的素数,有线性筛,然后分解a,然后dfs找所有的小于sqrt(a)的因子,

          由于前12个素数的乘积大于1e12了,所以这部分复杂度,大概是O(2^12)(一般还要略大,不过大不了多少,数组要开大)左右

         可以用这个估计(因为是求小于sqrt(a)的,可以除以2,当然这是空间常数)

          所以这部分复杂度是O(T*2^12)满的话(4000*4000)大概也就是几百万,这部分可以忽略不计

          主要的复杂度在分解素数里,因为1e6里面大概有7w多素数,这部分复杂度(最坏的情况a是大素数),大概是4000*70000,可以卡过,由于不可能都是这种数据

          所以还是可以过的

吐槽:然后我看了看网上的代码,都是先求出总的,然后暴力扫b减,结果居然过了,b是sqrt(a)的级别,是百万,4000*1e6,是4e9,TLE

        出题人太良心,没有卡这种的QAQ,感觉略坑啊

#include <cstdio>
#include <iostream>
#include <ctime>
#include <vector>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=1e6+5;
const int INF=0x3f3f3f3f;
int cnt;
bool v[N];
LL prime[80000];
void getprime(){
  for(int i=2;i*i<=N-5;++i)
    if(!v[i])
      for(int j=i*i;j<=N-5;j+=i)
        v[j]=1;
  for(int i=2;i<=N-5;++i)
  if(!v[i])prime[++cnt]=i;  
}
vector<LL>fac[2];
int divisors[5000],tot;
LL k;
void dfs(int pos,LL res){
   if(pos==fac[0].size()){
      divisors[++tot]=res;
      return;
   }
   for(LL i=0,now=1;i<=fac[1][pos];now*=fac[0][pos],++i){
     if(now*res>=k)break;
     dfs(pos+1,res*now);
   }
}
int main()
{
    getprime();
    int cas=0,T;
    scanf("%d",&T);
    while(T--){
       printf("Case %d: ",++cas);
       LL a,b;
       scanf("%lld%lld",&a,&b);
       k=sqrt(a);
       if(k*k!=a)++k;
       if(b>=k){
        printf("0\n");
        continue;
       }
       LL t=a;
       fac[0].clear(),fac[1].clear();
       for(int i=1;i<=cnt&&prime[i]*prime[i]<=t;++i){
         if(t%prime[i])continue;
         int tmp=0;
         fac[0].push_back(prime[i]);
         while(t%prime[i]==0)++tmp,t/=prime[i];
         fac[1].push_back(tmp);
       }
       if(t>1){
        fac[0].push_back(t);
        fac[1].push_back(1);
       }
       tot=0;
       dfs(0,1);
       int ans=0;
       for(int i=1;i<=tot;++i)
          if(divisors[i]>=b)++ans;
      printf("%d\n",ans);
    }
    return 0;
}
View Code

相关文章: