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})不对,因为会出现多次,但这也是笔者这种萌新容易混的地方

  • 相关阅读:
    猜年龄的问题
    某字符串可能包含26个英文字母,可能包含6种符号,可能包含3个数字,统计他们出现的个数
    指针变量前面类型的作用和意义
    二维数组 同时计算 练习题
    二维数组,行累加与列累加同时进行
    二维数组斜线扫描心得与分析
    二维数组扫描操作题
    LeetCode | Remove Duplicates from Sorted List II
    LeetCode | Remove Nth Node From End of List
    LeetCode | Palindrome Linked List
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11628189.html
Copyright © 2011-2022 走看看