zoukankan      html  css  js  c++  java
  • 清华集训2015-Day 1

    玛里苟斯

    一个大小为 (n) 的可重集合 (a) ,求 (mathbb E[x^k]) ,其中 (x)(a) 的一个子集的异或和。

    (nle 10^5,1le kle 5) ,保证答案小于 (2^{63})

    分析

    这题挺妙的呢。

    保证答案小于 (2^{63}) ,其实是告诉我们,答案的二进制位数 小于 64 位 。这就是说,对于一个 (k)(a_i) 的二进制位数 (m) 小于 (frac{64}{k})

    首先明确这样一件事情:若 (a) 中某一位有 1,那么在所有异或和中,这一位为 1 的占 (frac{1}{2}) 。也就是说,若这一位没有 1,那么所有异或和中这一位的期望为 0,否则为 (frac{1}{2})

    这是因为,对于其他元素的所有子集的异或和,异或上这一位与不异或这一位,必定有一个 1 一个 0 ,所以 1 一定占刚好 (frac{1}{2})

    (S)(n) 的所有子集的异或和的可重集合,对每一位分开考虑,那就有

    [egin{aligned} ext{ans}&=sum _{sin S}(sum_{i=0}^m 2^i[s_i=1])^k \ &=sum _{c_1=0}^msum _{c_2=0}^mcdotssum _{c_k=0}^mfrac{2^{sum c}}{2^n}sum _{sin S}[s_{c_p}=1,pin [1,k]] \ &=sum _{c_1=0}^msum _{c_2=0}^mcdotssum _{c_k=0}^m2^{sum c}P(a中c_i位上均为1) \ &=sum _{c_1=0}^msum _{c_2=0}^mcdotssum _{c_k=0}^m2^{sum c}frac{[a中c_i位上均有1]}{2^{c_i中不同的个数}} \ end{aligned} ]

    最后的形式可以对 (c) 中的位建线性基来求。总复杂度为 (O(m^{k+1}k)=O(64m^{k-1}))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long giant;
    inline char nchar() {
    	static const int bufl=1<<20;
    	static char buf[bufl],*a,*b;
    	return a==b && (b=(a=buf)+fread(buf,1,bufl,stdin),a==b)?EOF:*a++;
    }
    template<class T> inline T read() {
    	T x=0;
    	char c=nchar();
    	for (;!isdigit(c);c=nchar());
    	for (;isdigit(c);c=nchar()) x=x*10+c-'0';
    	return x;
    }
    const int maxn=1e5+1;
    const int maxj=64;
    const int maxk=5;
    template<typename T> inline void Max(T &x,T y) {x=max(x,y);}
    int b[maxk],c[maxk],n,m=0,k;
    giant ans=0,a[maxj],s[maxn];
    void dfs(int now) {
    	if (now==k) {
    		memset(b,0,sizeof b);
    		int gs=1;
    		for (int j=m;j>=0;--j) {
    			int x=0;
    			for (int i=k;i--;) if ((a[j]>>c[i])&1) x|=1<<i;
    			for (int i=k;i--;) if ((x>>i)&1) (b[i]?0:(b[i]=x,--gs)),x^=b[i];
    		}
    		int x=(1<<k)-1;
    		for (int i=k;i--;gs+=c[i]) if ((x^b[i])<x) x^=b[i];
    		if (!x) ans+=1ull<<gs;
    		return;
    	}
    	for (int i=0;i<=m;++i) c[now]=i,dfs(now+1);
    }
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    #endif
    	n=read<int>(),k=read<int>();
    	for (int i=1,j;i<=n;++i) {
    		giant &x=s[i]=read<giant>();
    		for (j=maxj;j--;) if ((x>>j)&1) break;
    		Max(m,j);
    	}
    	for (int i=1;i<=n;++i) {
    		giant x=s[i];
    		for (int j=m;j>=0 && x;--j) if ((x>>j)&1) (a[j]?0:(a[j]=x)),x^=a[j];
    	}
    	dfs(0);
    	printf("%lld%s
    ",ans>>1,ans&1?".5":"");
    	return 0;
    }
    

    主旋律

    一个 (n) 个点 (m) 条边的有向图,问有多少种删边方案使得得到的有向图仍然是一个强连通图。(nle 15,mle n(n-1))

    分析

    问题转化为有多少个点集不变的子图是强连通的。

    复习一下强连通图计数,即可得到这题的方法——不过是在这个图上进行。

    (f(S)) 为仅包含点集 (S)强连通图 个数。

    (g(S)) 为仅包含点集 (S)多个(包括 1 个)强连通块组成的图个数,带容斥系数,奇数个连通块加,偶数个连通块减

    (h(S)) 为仅包含点集 (S) 的有向图个数。

    上述图的边都属于原图的边集。

    有以下两条关系式:

    [egin{aligned} h(S)&=sum _{emptyset subsetneqq Tsubset S} g(T)h(Ssetminus T)2^{b(T,Ssetminus T)} \ g(S)&=f(S)-sum _{emptyset subsetneqq Tsubsetneqq S} f(T)g(Ssetminus T) end{aligned} ]

    其中 (b(A,B)) 表示 (|{(u,v)|,uin A,vin B,(u,v)in E}|)

    这可以用 in[x][s],out[x]][s] 分别表示 (x) 到一个集合的边数和集合到 (x) 的边数预处理。

    预处理的部分会用到莫比乌斯变换,即子集之和。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long giant;
    inline int read() {
        int x=0,f=1;
        char c=getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
        for (;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=15;
    const int maxm=maxn*(maxn-1);
    const int maxs=1<<maxn;
    const int q=1e9+7;
    inline int Plus(int x,int y) {return (x+=y)>=q?x-q:x;}
    inline void Pe(int &x,int y) {x=Plus(x,y);}
    inline int Multi(int x,int y) {return 1ll*x*y%q;}
    inline void Me(int &x,int y) {x=Multi(x,y);}
    inline int Sub(int x,int y) {return (x-=y)<0?x+q:x;}
    inline void Se(int &x,int y) {x=Sub(x,y);}
    inline int mi(int x,int y) {
        int ret=1;
        for (;y;y>>=1,Me(x,x)) if (y&1) Me(ret,x);
        return ret;
    }
    int n,m,S,in[maxn][maxs],out[maxn][maxs],e[maxs],b[maxs],two[maxm+1];
    int f[maxs],g[maxs],h[maxs];
    struct bian {
        int x,y;
    } a[maxm];
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("test.in","r",stdin);
    #endif
        two[0]=1;
        for (int i=1;i<=maxm;++i) two[i]=Multi(two[i-1],2);
        n=read(),m=read(),S=1<<n;
        for (int i=0;i<m;++i) {
            int &x=a[i].x=read()-1,&y=a[i].y=read()-1;
            ++in[y][1<<x],++out[x][1<<y],++e[(1<<x)|(1<<y)];
        }
        for (int i=0;i<n;++i) for (int j=0;j<n;++j) for (int s=0;s<S;++s) if ((s>>j)&1) Pe(in[i][s],in[i][s^(1<<j)]),Pe(out[i][s],out[i][s^(1<<j)]);
        for (int i=0;i<n;++i) for (int s=0;s<S;++s) if ((s>>i)&1) Pe(e[s],e[s^(1<<i)]);
        for (int s=1;s<S;++s) h[s]=two[e[s]];
        for (int s=1;s<S;++s) { // rig?
            for (int t=s;;t=(t-1)&s) {
                int &bt=b[t]=0;
                if (t==s) continue;
                if (!t) break;
                int o=s^t,x=__builtin_ctz(o);
                bt=Plus(Sub(b[t^(1<<x)],out[x][o^(1<<x)]),in[x][t]);
            }
            int &gs=g[s]=h[s];
            for (int t=s;t;t=(t-1)&s) Se(gs,Multi(Multi(g[t],h[s^t]),two[b[t]]));
        }
        for (int s=1;s<S;++s) {
            int v=__builtin_ctz(s),&fs=f[s]=g[s];
            for (int t=(s-1)&s;t;t=(t-1)&s) if ((t>>v)&1) Pe(fs,Multi(f[t],g[s^t]));
        }
        printf("%d
    ",f[S-1]);
        return 0;
    }
    

    奇数国

    简单题,线段树+压位。

  • 相关阅读:
    HDU 2544 最短路
    HDU 3367 Pseudoforest
    USACO 2001 OPEN
    HDU 3371 Connect the Cities
    HDU 1301 Jungle Roads
    HDU 1879 继续畅通工程
    HDU 1233 还是畅通工程
    HDU 1162 Eddy's picture
    HDU 5745 La Vie en rose
    HDU 5744 Keep On Movin
  • 原文地址:https://www.cnblogs.com/owenyu/p/7624446.html
Copyright © 2011-2022 走看看