zoukankan      html  css  js  c++  java
  • 数论容斥比较快速的做法和二分图判定1

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 32768K,其他语言65536K
    64bit IO Format: %lld

    题目描述

    珂朵莉想求:

    第x小的正整数v使得其最小的质因数为质数y,即正好有x-1个[1,v-1]之内的正整数满足其最小的质因数为质数y。

    若答案超过1000000000则输出0。

    输入描述:

    第一行两个正整数x,y

    输出描述:

    输出一个整数表示答案
    示例1

    输入

    2 3

    输出

    9
    示例2

    输入

    21000000 11

    输出

    0
    示例3

    输入

    1500 13

    输出

    93769

    说明

    3最小的质因数为3
    9最小的质因数为3
    第2小的最小质因数为3的数就是9

    备注:

    对于100%的数据,1 <= x,y <= 1000000000

    #include<cstdio>
    #include<cstring>
    #include<bitset>
    #include<algorithm>
    using namespace std;
    long long N=1e9,x,y,ans;
    long long p[18]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61};//18
    bitset<20000000>ok;
    void solve1(){
        int now=0;
        for(int i=2;i<y;i++) if(!ok[i])for(int j=i;j<=N;j+=i)  ok[j]=1;
        for(int i=1;i<N;++i) if(!ok[i]) {
            ++now;
            if(now==x) {ans=i;break;}
        }
        return;
    }
    long long cal(long long a,long long ord){
        if(p[ord]>=y) return a;
        if(!a) return 0;
        return cal(a,ord+1)-cal(a/p[ord],ord+1);
    }
    void solve2(){
        long long l=1,r=N;
        while(r>=l) {
            long long mid=(l+r)>>1;
            if(cal(mid,0)>=x) r=mid-1,ans=mid;
            else l=mid+1;
        }
    }
    int main(){
        scanf("%lld%lld",&x,&y);
        N/=y;
        if(y>61) solve1();
        else solve2();
        printf("%lld
    ",y*ans);
    }

    p>=x时,可以用1e9/x的筛算出来答案

    p<x时,考虑二分答案ans,然后容斥即可验证

    x60左右的时候最快

    题目描述

    珂朵莉给你一个无向图

    其有n个点,m条边

    对于每条边,她想知道删了这条边之后这个图是不是一个二分图

    输入描述:

    第一行两个整数n,m
    之后m行,每行两个数x,y表示有一条x和y之间的无向边
    第i个边的序号即为i

    输出描述:

    第一行输出一个整数,表示有多少边满足条件
    接下来一行,从小到大输出这些边的序号
    如果没有边满足条件,只输出一行一个数0,注意不要多输出换行
    示例1

    输入

    4 4
    1 2
    1 3
    2 4
    3 4

    输出

    4
    1 2 3 4

    说明

    对于100%的数据,有n , m<=1000000

    备注:

    对于100%的数据,有n , m<=1000000
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=2e6+88;
    bool vis[N];
    int n,m,cnt,ans[N];
    int head[N],tot=2,top;
    int bian[N<<1],f[N],g[N],pos[N];
    struct node{
        int to,next;
    }e[N<<1];
    void add(int u,int v){
        e[tot].to=v;e[tot].next=head[u];head[u]=tot++;
    }
    void dfs(int c,int et){
        vis[c]=1;
        pos[c]=++top;
        for(int i=head[c];i;i=e[i].next){
            if(bian[i]==-1) continue;
            if(!vis[e[i].to]) {
                bian[i]=bian[i^1]=-1;
                dfs(e[i].to,i>>1);
                f[et]+=f[i>>1];
                g[et]+=g[i>>1];
            }
            else {
                if(bian[i]==1) --f[et];
                if(bian[i]==2) --g[et];
                if(bian[i]==0) {
                    if((pos[c]-pos[e[i].to])&1) ++g[et],bian[i]=bian[i^1]=2;
                    else ++f[et],++cnt,bian[i]=bian[i^1]=1;
                }
            }
        }
        --top;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1,x,y;i<=m;++i) {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        for(int i=1;i<=n;++i) if(!vis[i]) dfs(i,0);
        int sum=0;
        if(!cnt) for(int i=1;i<=m;++i) ans[sum++]=i;
        else {
            for(int i=1;i<=m;++i) 
            if(f[i]==cnt&&g[i]==0) ans[sum++]=i;
            else if(cnt==1&&bian[i<<1]==1) ans[sum++]=i;
        }
        printf("%d
    ",sum);
        for(int i=0;i<sum;++i) printf("%d%c",ans[i],i==sum-1?'
    ':' ');
    }

    二分图即不能有奇环的无向图

    要使得所有的奇环消失,即要删去所有奇环的交上的边。

    但是如果删去奇环和偶环的交上的边,奇环和偶环就会重新组成一个新的奇环,所以在偶环上的边是不能删的。

    先随便搞个生成树出来,然后对于每个非树边在树上打标记,最后DFS一次即可以实现O( n + m )

  • 相关阅读:
    复利计算5.0
    读《构建之法》第4章有感
    实验二作业调度模拟程序
    观看与评价
    结对2.03
    做汉堡
    复利计算--结对
    《构建之法》第四章
    复利单利计算器单元测试
    实验一、命令解释程序的编写实验
  • 原文地址:https://www.cnblogs.com/mfys/p/8168031.html
Copyright © 2011-2022 走看看