省选模拟赛 让苍天知道我不认输(40分)
分析:强大的bitset......
对于每一个点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; void add(int x,int y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } 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); add(x,y); add(y,x); } 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; }