zoukankan      html  css  js  c++  java
  • [SDOI2013]泉(搜索+hash+容斥)

    题意

    给定(n)个时间,每个时间有六个权值,求恰好有(k)个权值对应相等的时间对的对数

    思路

    由于权值数量很少,可以枚举哪些权值相等,然后将每个时间的对应权值拿出来hash一遍,就可以得到有多少对时间的这些权值相同

    但是这样显然会算重复,比如有四个权值相同的时间对它的三个权值也会相同,于是可以开始容斥了

    (f_i)表示至少有(i)个权值对应相等的时间对的对数,即上面求出来的数组;设(g_i)表示恰好有(i)个权值对应相等的时间对的对数,即答案

    看起来应该是(f_i=Sigma {g_j},(ileq jleq 6)),但是其实(f_i)中会有不止一个(g_j),如(j=5,i=3)时,(f_3)会在(g_5)里面任选三个值加起来,所以会加(C(5,3))(g_5)

    (f_i=Sigma{C(j,i)*g_j},(ileq jleq 6))

    由上面可知,(g)的式子应该是(g_i=f_i-Sigma {g_j*C(j,i)},(i<jleq 6))

    Code

    #include<bits/stdc++.h>
    #define N 1000005
    #define re register
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const ull base = 1000000007;
    int n,k,a[N][7],st[7],top;
    ll f[8],g[8],C[10][10];
    ull has[N];
    
    template <class T>
    void read(T &x)
    {
    	char c;int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
    }
    
    void deal()
    {
    	for(re int i=1;i<=n;++i)
    	{
    		has[i]=0;
    		for(re int j=1;j<=top;++j) has[i]=has[i]*base+a[i][st[j]]+1;
    	}
    	sort(has+1,has+n+1);
    	ll len=0;
    	for(re int i=1;i<=n;++i)
    	{
    		if(has[i]!=has[i-1])
    		{
    			f[top]+=(len-1)*len/2;
    			len=1;
    		}
    		else ++len;
    	}
    	f[top]+=(len-1)*len/2;
    }
    int main()
    {
    	C[1][0]=C[1][1]=1;
    	for(re int i=2;i<10;++i)
    	{
    		C[i][0]=1;
    		for(re int j=1;j<=i;++j)
    		C[i][j]=C[i-1][j-1]+C[i-1][j];
    	}
    	read(n);read(k);
    	for(re int i=1;i<=n;++i)
    	  for(re int j=1;j<=6;++j)
    		read(a[i][j]);
    	for(re int i=0;i<64;++i)
    	{
    		top=0;
    		for(re int j=0;j<6;++j) if(i>>j&1) st[++top]=j+1;
    		deal();
    	}
    	for(re int i=6;i>=k;--i)
    	{
    		g[i]=f[i];
    		for(re int j=i+1;j<=6;++j)
    		g[i]-=g[j]*C[j][i];
    	}
    	cout<<g[k]<<endl;
    	return 0;
    }
    

    其实看懂了正解就知道(g_i=f_i-f_{i+1})不对,因为会出现多次,但这也是笔者这种萌新容易混的地方

  • 相关阅读:
    POJ 3253 Fence Repair
    POJ 2431 Expedition
    NYOJ 269 VF
    NYOJ 456 邮票分你一半
    划分数问题 DP
    HDU 1253 胜利大逃亡
    NYOJ 294 Bot Trust
    NYOJ 36 最长公共子序列
    HDU 1555 How many days?
    01背包 (大数据)
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11628189.html
Copyright © 2011-2022 走看看