SolveMe(ネタバレ注意)

年内に解くぞとか言ってたら普通に通ってしまった.
やるだけ.
以下ネタバレ.




















x=y=z=0の時以外はfもgも全単射じゃないとダメ.そうすると写像(置換)の合成が群になるので,条件は,左に乗る写像をf,右をgとすると,
{ \displaystyle
f^{x}gf^{y}gf^{z}=id
}
これを,
{ \displaystyle
f^{x+z}gf^{y}g=id
}
こうして,
{ \displaystyle
f^{x+z-y}h^{2}=id (ただしf^{y}gをhとおいた)
}
こうじゃ
bijなのでhをきめることとfをきめることが1:1対応しているので,t=x+z-yとおくと,
{ \displaystyle
f^{t}=g^{2}(hをgと置き直した)
}
これができればよい.
ここまでできた時点でまわりの怖い人に"じゃああとはやるだけじゃん","あとは600点"とか言われてつらくなる.

a-cycleの個数,とかによって明らかに数え方が変わってくるので,"a-cycleを何個使う"みたいな遷移を先に計算しておきたい気分になる.

{ \displaystyle
f^{t}=g^{2}をhとおくと,
}

結局f[i][j]="hに現れるi-cycle j個(それぞれ区別する)をfで表すのは何通りか"を持てばいい.これを計算するためには,

hに現れるi-cycleはt乗した結果(i/gcd(i,t))-cycleがgcd(i,t)個になる.t乗の結果x-cycleになるような奴らごとにループを回していく.
i-cycleそれぞれに関して,
dp[j][k] t乗の結果がi-cycleになるような数字のうちk個目まで使った時のほげ みたいな

説明がめんどくさくなった

#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <cstring>
#include <functional>
#include <cmath>
#include <complex>
using namespace std;
#define rep(i,n) for(int i=0;i<(n);++i)
#define rep1(i,n) for(int i=1;i<=(n);++i)
#define all(c) (c).begin(),(c).end()
#define fs first
#define sc second
#define pb push_back
#define show(x) cout << #x << " " << x << endl
typedef long long ll;
ll N,X,Y,Z,t,mod=1e9+7;
vector<int> A[1001],B[1001];//t乗したらi-cycleになるものたち,2
ll dp[1001][1001],f[1001][1001],g[1001][1001],fac[1001];
ll ret[1001][1001];
void add(ll &x,ll y){
	x+=y;
	if(x>=mod) x-=mod;
}
ll gcd(ll x,ll y){
	if(y==0) return x;
	return gcd(y,x%y);
}
ll pw(ll a,ll x){
	ll ret=1;
	while(x){
		if(x%2) ret=ret*a%mod;
		a=a*a%mod;
		x/=2;
	}
	return ret;
}
ll inv(ll a){
	return pw(a,mod-2);
}
ll invfac[1001];
int main(){
	fac[0]=1;
	rep(i,1000) fac[i+1]=fac[i]*(i+1)%mod;
	rep(i,1001) invfac[i]=inv(fac[i]);
	cin>>N>>X>>Y>>Z;
	t=abs(X+Z-Y);
	rep1(i,N){
		A[i/gcd(i,t)].pb(i);
	}
	dp[0][0]=1;
	rep1(i,N){
		rep(j,A[i].size()){
			int a=A[i][j];
			int m=a/i;
			rep(k,N/i+1) dp[j+1][k]=0;
			rep(k,N/i+1){//num of cycle
				for(int h=0;k+h*m<=N/i;h++){
					add(dp[j+1][k+h*m],dp[j][k]*invfac[h]%mod*inv(pw(m,h))%mod*pw(i,h*(m-1))%mod);
				}
			}
		}
		rep(k,N/i+1) f[i][k]=dp[A[i].size()][k]*fac[k]%mod;
	}
/*	rep1(i,N){
		cout<<"  cycle"<<i<<endl;
		rep(j,N/i+1){
			printf("f[%d][%d]=%lld\n",i,j,f[i][j]);
		}
		cout<<endl;
	}*/
	rep1(i,N){
		B[i/gcd(i,2)].pb(i);
	}
	dp[0][0]=1;
	rep1(i,N){
		rep(j,B[i].size()){
			int a=B[i][j];
			int m=a/i;
			rep(k,N/i+1) dp[j+1][k]=0;
			rep(k,N/i+1){//num of cycle
				for(int h=0;k+h*m<=N/i;h++){
					add(dp[j+1][k+h*m],dp[j][k]*invfac[h]%mod*inv(pw(m,h))%mod*pw(i,h*(m-1))%mod);
				}
			}
		}
		rep(k,N/i+1) g[i][k]=dp[B[i].size()][k]*fac[k]%mod;
	}
/*	rep1(i,N){
		cout<<"  cycle"<<i<<endl;
		rep(j,N/i+1){
			printf("g[%d][%d]=%lld\n",i,j,g[i][j]);
		}
		cout<<endl;
	}*/
	ret[0][0]=1;
	rep1(i,N){ //using cycle
		rep(j,N+1){
			for(int k=0;i*k+j<=N;k++){ //num
				add(ret[i][i*k+j],ret[i-1][j]*f[i][k]%mod*g[i][k]%mod*inv(pw(i,k))%mod*invfac[k]%mod);
			}
		}
	}
	ll ans=ret[N][N]*fac[N]%mod;
	if(X+Y+Z==0) ans=ret[N][N]*pw(N,N)%mod;
	cout<<ans<<endl;
}

何が言いたかったかというと,SolveMeは や る だ け .