版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/85389523
题面传送门
解析:
直接解方程可以得到
利用二次剩余直接解出 。
然后分情况讨论。
如果有解,一边dfs树的时候一边用map 统计一下就好了。
如果无解,dfs只需要记录它上方有多少个祖先的权值为0,然后看它自己的权值是否为0,那么它和祖先就能组成合法点对,记录就行了。
另外,本校OJ上的数据是我造的。。。https://blog.csdn.net/zxyoi_dreamer/article/details/85392259
代码:
#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define puts put_s
#define cs const
namespace IO{
namespace READONLY{
cs int Rlen=1<<18|1;
char buf[Rlen],*p1,*p2;
}
inline char get_char(){
using namespace READONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline ll getint(){
re ll num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
inline ll mul(cs ll &a,cs ll &b,cs ll &mod){return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;}
namespace Find_root{
inline ll quickpow(ll a,ll b,cs ll &mod,ll res=1){
for(;b;b>>=1,a=mul(a,a,mod))if(b&1)res=mul(res,a,mod);
return res;
}
ll W,Mod;
struct Complex{
ll x,y;
Complex(cs ll &_x=0,cs ll &_y=0):x(_x),y(_y){}
inline friend Complex operator*(cs Complex &a,cs Complex &b){
return Complex(
(mul(a.x,b.x,Mod)+mul(mul(a.y,b.y,Mod),W,Mod))%Mod,
(mul(a.x,b.y,Mod)+mul(a.y,b.x,Mod))%Mod
);
}
};
inline Complex quickpow(Complex a,ll b){
re Complex res(1,0);
for(;b;b>>=1,a=a*a)if(b&1)res=res*a;
return res;
}
inline ll solve(ll a,ll p){
a%=p;if(a==0)return 0;
if(quickpow(a,(p-1)>>1,p)==p-1)return -1;
re ll b;
Mod=p;
while(true){
b=rand()%p;
W=(mul(b,b,p)-a+p)%p;
if(quickpow(W,(p-1)>>1,p)==p-1)break;
}
return quickpow(Complex(b,1),(p+1)>>1).x;
}
}
int n;
ll p,A,B;
cs int N=100005;
vector<int> edge[N];
inline void addedge(cs int &u,cs int &v){
edge[u].push_back(v);
}
ll a[N];
ll a1,a2,ans;
tr1::unordered_map<ll,int> cnt;
inline void dfs1(int u){
ans+=cnt[a[u]];
re ll v1=mul(a[u],a1,p),v2=mul(a[u],a2,p);
v1==v2?++cnt[v1]:(++cnt[v1],++cnt[v2]);
for(int re e=0;e<edge[u].size();++e)
dfs1(edge[u][e]);
v1==v2?--cnt[v1]:(--cnt[v1],--cnt[v2]);
}
int now;
inline void dfs2(int u){
if(!a[u])ans+=now,++now;
for(int re e=0;e<edge[u].size();++e)
dfs2(edge[u][e]);
if(!a[u])--now;
}
signed main(){
n=getint();p=getint();A=getint();B=getint();
for(int re i=1;i<=n;++i)a[i]=getint();
for(int re i=2;i<=n;++i)addedge(getint(),i);
ll det=Find_root::solve((mul(A,A,p)-4*B%p+p)%p,p);
if(det==-1)dfs2(1);
else{
ll inv2=p-(p/2);
a1=mul((det-A+p)%p,inv2,p);
a2=mul((-det-A+p+p)%p,inv2,p);
dfs1(1);
}
printf("%lld",ans);
return 0;
}