# 省选模拟赛 让苍天知道我不认输(40分)

对于每一个点i,其bitset f[i][j]表示f(t(i -> j)). 枚举两个点i,j. 如果f[i][j] = 1. 那么f[i] & f[j]中1的个数就是i,j的贡献. 否则f[i]和f[j]相同位置处0的个数就是贡献. 先以每个点为起点dfs一次就能预处理出f了.

用bitset主要是因为想确定i,j连到的是不是同一个点. 直接求方案数可能不合法.

#include <cstdio>
#include <bitset>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 1010;
int n,y,k,r,a[maxn],head[maxn],to[maxn * 2],nextt[maxn * 2],tot = 1,vis[maxn];
bitset <maxn> f[maxn],b,temp1,temp2,temp;
long long ans;

{
to[tot] = y;
}

void dfs(int S,int u,int z,int ki)
{
int temp = (z + a[u] * ki % y) % y;
if (temp == r)
f[S][u] = 1;
else
f[S][u] = 0;
vis[u] = 1;
for (int i = head[u];i;i = nextt[i])
{
int v = to[i];
if (!vis[v])
{
int tmp = ki * k % y;
dfs(S,v,temp,tmp);
}
}
}

int main()
{
scanf("%d%d%d%d",&n,&y,&k,&r);
for (int i = 1; i <= n; i++)
scanf("%d",&a[i]);
for (int i = 1; i < n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
}
for (int i = 1; i <= n; i++)
{
memset(vis,0,sizeof(vis));
dfs(i,i,0,1);
}
for (int i = 1; i <= n; i++)
b[i] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (f[i][j] == 1)
{
temp = f[i] & f[j];
ans += temp.count();
}
else
{
temp1 = f[i] ^ b;
temp2 = f[j] ^ b;
temp = temp1 & temp2;
ans += temp.count();
}
}
}
printf("%lld\n",ans);

return 0;
}
posted @ 2018-04-04 14:38  zbtrs  阅读(388)  评论(0编辑  收藏  举报