• 2017-2-15做题记录


    [9018]1930 国家

    题目大意:给定A、B序列,A序列中的数若满足a xor b%2=1则连边,B序列中数若满足a xor b%2=0或a or b二进制下有奇数个1则连边,再给出A和B的连边关系,求最大团。(数据组1:A<=80,B<=100;数据组2:A<=5,B<=1500)

    思路:这题是本校以前某次测试的题,当时看了看感觉不可做就跳过了……观察发现,最大团中A序列的点不会超过2个(因为a和b必须一奇一偶才能连边,奇或偶超过1个必然不是团),于是可以先枚举取A中的哪些点,然后取出相连的B中的点,按奇偶分成二分图,考虑最小割,若二分图两边一对点或起来有偶数个1则不能一起选入答案,连INF,然后跑一遍模板就能A了。复杂度O(能过)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x=0;char c;
        while((c=getchar())<'0'||c>'9');
        for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MA 80
    #define MB 1500
    #define MV 1500
    #define ME 562500
    #define S MV+1
    #define T MV+2
    #define INF 0x3fffffff
    struct edge{int nx,t,w;}e[ME*2+5];
    int h[MV+5],en,d[MV+5],q[MV+5],qn,c[MV+5];
    int g[MA+5][MB+5],va[MA+5],vb[MB+5],ql[MB+5],qln,qr[MB+5],qrn,s[1<<16];
    inline void ins(int x,int y,int w)
    {
        e[++en]=(edge){h[x],y,w};h[x]=en;
        e[++en]=(edge){h[y],x,0};h[y]=en;
    }
    int bfs()
    {
        int i,j;
        memset(d,0,sizeof(d));
        for(d[q[i=qn=0]=S]=1;i<=qn;c[q[i]]=h[q[i]],++i)for(j=h[q[i]];j;j=e[j].nx)
            if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1;
        return d[T];
    }
    int dfs(int x,int r)
    {
        if(x==T)return r;
        int u=0,k;
        for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[e[i].t]==d[x]+1)
        {
            k=dfs(e[i].t,r-u<e[i].w?r-u:e[i].w);
            u+=k;e[i].w-=k;e[i^1].w+=k;
            if(u==r)return r;
        }
        return d[x]=0,u;
    }
    inline int cal(int x){return s[x>>16]+s[x&((1<<16)-1)];}
    int dinic()
    {
        int i,j,r=0;
        memset(h,0,sizeof(h));en=1;
        for(i=1;i<=qln;++i)ins(S,i,1);
        for(i=1;i<=qrn;++i)ins(i+qln,T,1);
        for(i=1;i<=qln;++i)for(j=1;j<=qrn;++j)
            if(cal(ql[i]|qr[j])%2==0)ins(i,j+qln,INF);
        while(bfs())r+=dfs(S,INF);
        return r;
    }
    int main()
    {
        int t=read(),a,b,m,i,j,k,ans;
        for(i=0;i<16;++i)for(j=1<<i;j<1<<i+1;++j)s[j]=s[j-(1<<i)]+1;
        while(t--)
        {
            a=read();b=read();m=read();
            for(i=1;i<=a;++i)va[i]=read();
            for(i=1;i<=b;++i)vb[i]=read();
            memset(g,0,sizeof(g));
            while(m--)i=read(),g[i][read()]=1;
            for(qln=qrn=0,i=1;i<=b;++i)(vb[i]&1?ql[++qln]:qr[++qrn])=vb[i];
            ans=b-dinic();
            for(i=1;i<=a;++i)
            {
                for(qln=qrn=0,j=1;j<=b;++j)if(g[i][j])
                    (vb[j]&1?ql[++qln]:qr[++qrn])=vb[j];
                ans=max(ans,qln+qrn+1-dinic());
            }
            for(i=1;i<=a;++i)for(j=i+1;j<=a;++j)if(va[i]%2!=va[j]%2)
            {
                for(qln=qrn=0,k=1;k<=b;++k)if(g[i][k]&&g[j][k])
                    (vb[k]&1?ql[++qln]:qr[++qrn])=vb[k];
                ans=max(ans,qln+qrn+2-dinic());
            }
            printf("%d
    ",ans);
        }
    }

    [9018]1667 吴桐学长和网管

    题目大意:从1~M中选出N个不同的数,求其倒数和等于X/Y的方案数。(N,M<=50,X,Y<=100,保证方案数不超过10^5)

    思路:好像这题正解直接搜索剪枝就过了?我看到这题就想折半搜索,先枚举前M/2,然后Hash存起来,再枚举后M/2算答案,精度有点玄学我手写了个分数类型(不知道会不会爆LL),一开始用的std::map,1秒多才过,我就把题目时限从1s改成2s了哈哈哈,后来手写了个期望O(1)的map,总算卡到1s内。复杂度期望O(2^(M/2))

    #include<cstdio>
    #define MOD 523333
    #define ME 1000000
    int gcd(int x,int y){return y?gcd(y,x%y):x;}
    struct fs
    {
        long long x,y;
        friend bool operator<(fs a,fs b){return a.x*b.y<b.x*a.y;}
        fs operator+(fs b)
        {
            int xx=x*b.y+b.x*y,yy=y*b.y,g=gcd(xx,yy);
            return (fs){xx/g,yy/g};
        }
    }f;
    struct edge{int nx,t;fs s;}e[ME+5];
    int n,ans,en;
    inline void ins(int*h,int x,fs s){e[++en]=(edge){h[x],0,s};h[x]=en;}
    struct map
    {
        int h[MOD];
        int&operator[](fs a)
        {
            int x=((a.x*23333+a.y)%MOD+MOD)%MOD,i;
            for(i=h[x];i;i=e[i].nx)if(e[i].s.x==a.x&&e[i].s.y==a.y)return e[i].t;
            ins(h,x,a);if(en>ME)puts("X");return e[en].t;
        }
    }mp[26];
    void dfs1(int x,int h,int k,fs s)
    {
        if(k>n||f<s)return;
        if(x>h){++mp[k][s];return;}
        dfs1(x+1,h,k,s);dfs1(x+1,h,k+1,s+(fs){1,x});
    }
    void dfs2(int x,int h,int k,fs s)
    {
        if(k>n||f<s)return;
        if(x>h){ans+=mp[n-k][f+(fs){-s.x,s.y}];return;}
        dfs2(x+1,h,k,s);dfs2(x+1,h,k+1,s+(fs){1,x});
    }
    int main()
    {
        int m,x,y;
        scanf("%d%d%d%d",&n,&m,&f.x,&f.y);
        dfs1(1,m>>1,0,(fs){0,1});dfs2((m>>1)+1,m,0,(fs){0,1});
        printf("%d",ans);
    }
  • 相关阅读:
    Chap-6 6.1~6.3 程序装载
    X Window基础二(转)
    X Window基础一(转)
    Linux基础命令 su与sudo的区别
    Chap-4 Section 4.6 链接控制过程
    Chap-4 Section 4.5 静态库链接
    ceph的CRUSH数据分布算法介绍
    使用ffmpeg捕获USB外部摄像头视频流
    使用ffserver实现转发实时流媒体(摄像头捕获)
    内存映射文件(专门读写大文件)
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170215P.html
Copyright © 2020-2023  润新知