6495. 【GDOI2020模拟03.08】死星

题目描述


题解

考虑用总数-不合法数

因为相同情况只有轮换和翻转,所以总数=\(n^{\underline{K}}/2K\)

K=3时,不合法的情况只有三元组的一个点有两条向外的边,并且每个三元组中只有一个这样的点,统计一下即可

K=4时减只有一个向外的加有两个向外的,K=5同理,只不过两个向外的点连了一个共同点,两个不同点

bitset即可做到O(n^3/ω),需要预处理每个点的出度

注意细节

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;

bitset<2001> a[2001],A;
int m,i,j,k,l,x,y;
char st[1000001];
ll c[2001],n,ans,s,s1,s2;

void nxt()
{
	if (y<n) ++y;
	else ++x,y=x+1;
}

int main()
{
	freopen("deathstar.in","r",stdin);
	#ifdef file
	freopen("deathstar.out","w",stdout);
	#endif
	
	scanf("%lld%d",&n,&m);
	scanf("%s",st);l=strlen(st);
	x=1;y=2;
	fo(i,0,l-1)
	{
		if (st[i]>='0' && st[i]<='9')
		j=st[i]-'0';
		else
		j=st[i]-'A'+10;
		
		if (j&8) a[x][y]=1,++c[x]; else a[y][x]=1,++c[y]; nxt(); if (x==n) break;
		if (j&4) a[x][y]=1,++c[x]; else a[y][x]=1,++c[y]; nxt(); if (x==n) break;
		if (j&2) a[x][y]=1,++c[x]; else a[y][x]=1,++c[y]; nxt(); if (x==n) break;
		if (j&1) a[x][y]=1,++c[x]; else a[y][x]=1,++c[y]; nxt(); if (x==n) break;
	}
	
	switch (m)
	{
		case 3:{
			ans=n*(n-1)*(n-2)/6;
			
			fo(i,1,n)
			{
				s=c[i];
				ans-=s*(s-1)/2;
			}
			break;
		}
		case 4:{
			ans=n*(n-1)*(n-2)*(n-3)/8;
			
			fo(i,1,n)
			{
				s=c[i];
				ans-=s*(s-1)/2*(n-3);
			}
			
			fo(i,1,n-1)
			{
				fo(j,i+1,n)
				{
					s=(a[i]&a[j]).count();
					ans+=s*(s-1)/2;
				}
			}
			break;
		}
		case 5:{
			ans=n*(n-1)*(n-2)*(n-3)*(n-4)/10;
			
			fo(i,1,n)
			{
				s=a[i].count();
				ans-=s*(s-1)/2*(n-3)*(n-4);
			}
			
			fo(i,1,n-1)
			{
				fo(j,i+1,n)
				{
					A=a[i]&a[j];
					s=A.count();
					s1=c[i]-s-a[i][j];
					s2=c[j]-s-a[j][i];
					
					ans+=s*s1*s2+s*s1*(s-1)+s*(s-1)*s2+s*(s-1)*(s-2);
				}
			}
			break;
		}
	}
	
	printf("%lld\n",ans);
	
	fclose(stdin);
	fclose(stdout);
	
	return 0;
}
posted @ 2020-03-10 22:24  gmh77  阅读(232)  评论(0编辑  收藏  举报