数论容斥比较快速的做法和二分图判定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\n",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\n",sum);
    for(int i=0;i<sum;++i) printf("%d%c",ans[i],i==sum-1?'\n':' ');
}

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

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

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

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

posted @ 2018-01-01 17:44  Billyshuai  阅读(308)  评论(0编辑  收藏  举报