CCPC-Wannafly Winter Camp Day7

A.迷宫

有一个 n n n 个点 n − 1 n-1 n1 条边的无向连通图迷宫,其中有些点上面有人.
现在所有人的目标都是逃离这个迷宫,而迷宫的出口是 1 号点,每一时刻,会依次发生以下的事情:
1.在点 x 上的人选择一个点 f ( x ) f(x) f(x) 作为目标,要求 f ( x ) f(x) f(x) 必须是 x x x,或者与 x x x 有边相连的点,且对于 x ≠ y x\neq y x̸=y,有 f ( x ) ≠ f ( y ) f(x)\neq f(y) f(x)̸=f(y)
2.在点 x x x 上的人移动到 f ( x ) f(x) f(x)
3.在点 1 1 1 号点上的人成功逃脱,从这个游戏里消失
现在你需要求的是:让所有人都成功逃脱至少需要多少时间.

贪心,先让深度小的节点上的人逃生。
每个人的逃生时间为 m a x ( 他 理 论 最 小 逃 生 时 间 , 上 一 个 人 的 逃 生 时 间 + 1 ) max(他理论最小逃生时间 , 上一个人的逃生时间+1) max(,+1)

#include 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i
#define ForD(i,n) for(int i=n;i>0;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector 
#define pi pair
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
	return x*f;
} 
#define MAXN (112345)
int n,a[MAXN],dep[MAXN]={};
vi e[MAXN];
void dfs(int x,int fa){
	dep[x]=dep[fa]+1;
	for(auto v:e[x]) if(v^fa) {
		dfs(v,x);
	}
}
int main()
{
//	freopen("A.in","r",stdin);
//	freopen(".out","w",stdout);
	cin>>n;For(i,n) a[i]=read();
	For(i,n-1) {
		int u=read(),v=read();e[u].pb(v);e[v].pb(u);
	}
	dfs(1,0);
	vi v;
	For(i,n) if(a[i]) v.pb(dep[i]-1);
	sort(ALL(v));
	int ans=0,p=0;
	for(int x:v) {
		p=max(p+1,x);
	}
	cout<<p<<endl;
	return 0;
}

B.重新定义字典序

不会

C. 斐波那契数列

求$ sum {n=1}^R {Fib(n)&(Fib(n-1)} $

include<bits/stdc++.h>
using namespace std;
/*long long f[300];
int main()
{
	f[1]=f[2]=1;
	printf("%d %d\n",1,1);
	printf("%d %d\n",2,1);
	for(int i=3;i<=240;i++){
		f[i]=f[i-2]+f[i-1];
		printf("%d %lld\n",i,f[i]-(f[i]&(f[i]-1)));
	}
}*/

typedef long long LL;
const int MOD=998244353;
struct Matrix{
	int a[2][2];
	void zero(){
		for (int i = 0; i < 2; i++)
			memset(a[i], 0, sizeof(int)*2);
	}
	void one(){
		zero();
		for (int i = 0; i < 2; i++)a[i][i] = 1;
	}
	Matrix operator * (const Matrix& x)const{
		Matrix r; r.zero();
		for (int i = 0; i < 2; i++){
			for (int j = 0; j < 2; j++){
				for (int k = 0; k < 2; k++)
					r.a[i][k] = (r.a[i][k] + (LL)a[i][j] * x.a[j][k]) % MOD;
			}
		}
		return r;
	}
	Matrix operator ^ (LL k)const{
		Matrix r, t = *this; r.one();
		for (; k; k >>= 1){
			if (k & 1)r = r * t;
			t = t * t;
		}
		return r;
	}
};
int fib(LL n){
	Matrix mt;
	mt.a[0][0]=1;mt.a[0][1]=1;
	mt.a[1][0]=1;mt.a[1][1]=0;
	return (mt^n).a[1][0];
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--){
		LL n;
		scanf("%lld",&n);
		LL sum=fib(n+2);
		sum--;
		sum-=n;
		sum-=n/3;
		sum+=2*(n/6);
		for(int i=3;i<=62;i++){
			sum-=(1LL<<i)%MOD*((n+(3LL<<(i-2)))/(3LL<<(i-1)))%MOD;
		}
		sum=((sum%MOD)+MOD)%MOD;
		printf("%lld\n",sum);
	}
}

D. 二次函数

给你3个关于x的二次函数 f ( x ) , g ( x ) , h ( x ) f(x),g(x),h(x) f(x),g(x),h(x),要求给出 x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3,使得 f ( x 1 ) , g ( x 2 ) , h ( x 3 ) f(x_1),g(x_2),h(x_3) f(x1),g(x2),h(x3) 这三个数中至少有两个数相同.
系数绝对值都小于等于 1 0 4 10^4 104,
∣ x 1 ∣ , ∣ x 2 ∣ , ∣ x 3 ∣ ≤ 1 0 18 |x_1|,|x_2|,|x_3|\le 10^{18} x1,x2,x31018
分类讨论,
其实可以通过配方把一次项系数拿掉。

#include
#define LL long long
using namespace std;
int a1,b1,a2,b2,a3,b3;
int x1,x2;
bool check(LL a1,LL b1,LL x1,LL a2,LL b2,LL x2){
	return x1*x1+a1*x1+b1==x2*x2+a2*x2+b2;
}
bool solve(int a1,int b1,int a2,int b2)
{
	if(abs((a1-a2))%2==1){
		int k=(a2-a1+1)/2;
		x2=-(k*k+k*a1+b1-b2);
		x1=x2+k;
	//	if(!check(a1,b1,x1,a2,b2,x2)){printf("Error");}
	//	else printf("Yes1");
		return true;
	}
	else{
		int kk=(a2-a1)/2;
		for(int k=kk-2;k<=kk+2;k++){
			if(k==kk)continue;
			if((k*k+k*a1+b1-b2)%(2*k+a1-a2))continue;
			x2=-(k*k+k*a1+b1-b2)/(2*k+a1-a2);
			x1=x2+k;
	//		if(!check(a1,b1,x1,a2,b2,x2)){printf("Error");}
	//		else printf("Yes2");
			return true;
		}
	}
	return false;
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d%d%d%d",&a1,&b1,&a2,&b2,&a3,&b3);
		solve(a1,b1,a2,b2)||solve(a1,b1,a3,b3)||solve(a2,b2,a3,b3);
		if(check(a1,b1,x1,a2,b2,x2))printf("%d %d %d\n",x1,x2,0);
		else if(check(a1,b1,x1,a3,b3,x2))printf("%d %d %d\n",x1,0,x2);
		else if(check(a2,b2,x1,a3,b3,x2))printf("%d %d %d\n",0,x1,x2);
		//else printf("Error");
	}
}

E.线性探查法

#include 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i
#define ForD(i,n) for(int i=n;i>0;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector 
#define pi pair
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
	return x*f;
} 
#define MAXN (112345+10)

int b[MAXN],a[MAXN];
set<int> S;
int get(int p) {
	set<int> :: iterator it = S.lower_bound(p);
	if(it==S.end()) {
		it=S.lower_bound(-1);
	}
	return *it;
}
bool vis[MAXN]={};
int main()
{
//	freopen("E.in","r",stdin);
//	freopen(".out","w",stdout);
	int n=read();
	Rep(i,n) {
		b[i]=read();
	}
	priority_queue< pi ,vector< pi  >  , greater< pi > > q;
	Rep(i,n) if(b[i]%n==i) q.push(mp(b[i],i)),vis[i]=1;
	int l=0;
	Rep(i,n) S.insert(i);
	while(!q.empty()) {
		pi x=q.top();q.pop();
		a[++l]=x.fi;
		if(l==n) break;
		S.erase(x.se);
		int ad_pos=get(x.se);
		if(!vis[ad_pos]) {
			int c=get(b[ad_pos]%n);
			if (c == ad_pos) {
				q.push(mp(b[ad_pos],ad_pos));vis[ad_pos]=1;
			}
		}
	}
	PRi(a,n)	
	return 0;
}

F. 逆序对!

给定长度为 n 的两两不相同的整数数组 b[1…n],定义 f(y)为:将 b 每个位置异或上 y 后,得到的新数组的逆序对个数。
需要求 ∑ i = 1 m f ( i ) \sum_{i=1}^{m}f(i) i=1mf(i)
由于答案可能很大,你只需要输出答案对 998244353取模后的值
数位dp,设 d p i dp_i dpi 1   m 1~m 1 m中第i位为1的数的个数。
排序 b b b,枚举 b i b_i bi,从高位向低位枚举x,设和 b i b_i bi的n…x+1位均相同的 b j b_j bj区间为 [ l , r ] [l,r] [l,r]
要么这一位必须填 1 / 0 1/0 1/0,要么这一位可以填任意值(不影响答案)。

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i
#define MEM(a) memset(a,0,sizeof(a));
#define F (998244353)
typedef long long ll;
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
namespace CA{
	#define MAXN (32)
	int a[MAXN];
	ll f[MAXN][2][2][2];
	//first i,jth num,k is_0qiandao,y is==n 
	ll dp[MAXN];
	int n;
	void calc(ll m) {
		MEM(dp)
		n=0;
		while(m) a[++n]=m%2,m/=2;
		reverse(a+1,a+1+n);
		For(x,n) {
			MEM(f)
			f[0][0][0][1]=1;
			Rep(i,n) {
				Rep(j,2) Rep(k,2) Rep(y,2) {
					if (f[i][j][k][y]) {
						Rep(t,2) {
							int nk=k|(t>0);
							int ny=(y&&t==a[i+1]);
							if (y&&t>a[i+1]) continue;
							if(x==i+1 && !t) continue;
									
							upd(f[i+1][t][nk][ny],f[i][j][k][y]);
						}
					}
				}
			}
			int k=1;
			Rep(j,2) Rep(y,2) {
				upd(dp[x],f[n][j][k][y]);
			}
		}
		reverse(dp+1,dp+1+n);
		For(i,n) dp[i-1]=dp[i];
		dp[n]=0;
	}
}
/*int main()
{
//	freopen("E.in","r",stdin);
//	freopen(".out","w",stdout);
	CA::calc(4);

	return 0;
}*/



#include
using namespace std;
const int MOD=998244353;
typedef long long LL;
struct Node{
	int x,i;
	bool operator < (const Node & t)const{
		return x<t.x;
	}
}a[100001];
LL ans;
int n,m;
int tree[100001];
void add(int i,int n,int x)
{
	for(;i<=n;i+=i&-i)
		tree[i]+=x;
}
int sum(int i){
	int ret=0;
	for(;i;i-=i&-i)
		ret+=tree[i];
	return ret;
}
void solve(int bit,int l,int r)
{
	if(l>r)return;
	int mid=l;
	LL res=0,res2;
	while(mid<=r&&(a[mid].x&((1<<(bit+1))-1))<(1<<bit))mid++;
	for(int i=r;i>=mid;i--)
		add(a[i].i,n,1);
	for(int i=l;i<mid;i++)
		res+=sum(a[i].i);
	res2=(LL)(r-mid+1)*(mid-l)-res;
	(ans+=res2%MOD*CA::dp[bit]+res%MOD*(m-CA::dp[bit]))%=MOD;
	for(int i=r;i>=mid;i--)
		add(a[i].i,n,-1);
	if(bit)solve(bit-1,l,mid-1);
	if(bit)solve(bit-1,mid,r);
}
int main()
{
	scanf("%d%d",&n,&m);
	CA::calc(m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i].x);
		a[i].i=i;
	}
	sort(a+1,a+n+1);
	solve(29,1,n);
	printf("%lld\n",(ans%MOD+MOD)%MOD);
}

G.抢红包机器人

#include 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i
#define ForD(i,n) for(int i=n;i>0;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector 
#define pi pair
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
	return x*f;
} 
#define MAXN (101)
queue<int> q;
bool b[MAXN]={};
int g[MAXN][MAXN]={},f[MAXN][MAXN]={};
int main()
{
//	freopen("g.in","r",stdin);
//	freopen(".out","w",stdout);
	int n=read(),m=read();
	For(i,m) {
		int k=read();
		For(j,k) {
			f[i][j]=read();
		}
		For(j,k-1){
			int l=j+1;
			g[f[i][l]][f[i][j]]=1;
		}
	}
	int Ans=1e9;
	For(xnode,n) {
		MEM(b)
		b[xnode]=1;q.push(xnode);
		while(!q.empty()) {
			int x=q.front();
			q.pop();
			For(i,n) if(!b[i] && g[x][i]) b[i]=1,q.push(i);
		}
		int ans=0;
		For(i,n) ans+= b[i];
//		cout<
		gmin(Ans,ans)
	}
	
	
	cout<<Ans<<endl;
	
	return 0;
}

H.同构

给定 n,我们定义一张无向图是好的,当且仅当它无重边无自环,且每个点的度数都是 n-3。你需要求出最多能找出多少张好的图,使得它们两两不同构.
输出答案对 998244353 取模后的值
n ≤ 1 e 5 n\le 1e5 n1e5

补图,转成环,划分数

#include
#include
#include
using namespace std;
inline int mul(int a, int b, int mod){ return (long long)a*b%mod; }
int power(int a, int b, int mod){
	int ret = 1;
	for (int t = a; b; b >>= 1){
		if (b & 1)ret = mul(ret, t, mod);
		t = mul(t, t, mod);
	}
	return ret;
}
int cal_root(int mod)
{
	int factor[20], num = 0, m = mod - 1, s = m;
	for (int i = 2; i * i <= s; i++){
		if (s % i == 0){
			factor[num++] = i;
			while (s % i == 0)s /= i;
		}
	}
	if (s != 1)factor[num++] = s;
	for (int i = 2;; i++){
		int j = 0;
		for (; j < num && power(i, m / factor[j], mod) != 1; j++);
		if (j == num)return i;
	}
}
template<int MOD, int ROOT>
void fft_main(int a[], int len, bool reverse)
{
	for (int i = 1, j = len / 2; i < len - 1; i++) {
		if (i < j) swap(a[i], a[j]);
		for (int k = len; j < k; k >>= 1, j ^= k);
	}
	for (int s = 1; s < len; s <<= 1){
		int t = (MOD - 1) / (s * 2);
		int step = power(ROOT, reverse ? MOD - 1 - t : t, MOD);
		for (int j = 0; j < len; j += 2 * s){
			int cur = 1;
			for (int k = j; k < j + s; k++){
				int u = a[k], t = mul(cur, a[k + s], MOD);
				a[k] = (unsigned int)(u + t) % MOD;
				a[k + s] = (unsigned int)(u - t + MOD) % MOD;
				cur = mul(cur, step, MOD);
			}
		}
	}
	if (reverse){
		int t = power(len, MOD - 2, MOD);
		for (int i = 0; i < len; i++)
			a[i] = mul(a[i], t, MOD);
	}
}
//确保数组中的数小于mod(mod<2^30),数组需留足2^(logn向上取整+1)的空间
//并且mod为形如m*2^k+1的素数,2^k>=2*n
template<int MOD, int ROOT>
void fft(int a[], int b[], int n)
{
	int len = 1;
	while (len < 2 * n)len <<= 1;
	memset(a + n, 0, sizeof(int)*(len - n));
	memset(b + n, 0, sizeof(int)*(len - n));
	fft_main<MOD, ROOT>(a, len, 0);
	fft_main<MOD, ROOT>(b, len, 0);
	for (int i = 0; i < len; i++)
		a[i] = mul(a[i], b[i], MOD);
	fft_main<MOD, ROOT>(a, len, 1);
}

#define MAXN 131072
int par[2*MAXN];
int dp2[2*MAXN],dp[350][MAXN];
template<int MOD, int ROOT>
void calParNumber(int n)
{
	int s=sqrt(n)+1;
	par[0]=1;
	for(int i=3;i<s;i++){
		for(int j=i;j<=n;j++)
			(par[j]+=par[j-i])%=MOD;
	}
	dp[0][0]=1;dp2[0]=1;
	for(int i=1;i<=s;i++){
		for(int j=s;j<=n;j++){
			dp[i][j]=(dp[i-1][j-s]+dp[i][j-i])%MOD;
			(dp2[j]+=dp[i][j])%=MOD;
		}
	}
	fft<MOD,ROOT>(par,dp2,n+1);
}强壮的排列
int main()
{
	calParNumber<998244353,3>(100000);
	int n;
	scanf("%d",&n);
	printf("%d",par[n]);
}

I. 集合

J.强壮的排列

我们定义一个 1... n 1...n 1...n 的排列 p 是强壮的,当且仅当 n 是奇数,且对于所有 1 ≤ i ≤ n − 1 2 1\leq i\leq \frac{n-1}{2} 1i2n1 p [ 2 i ] > m a x ( p [ 2 i − 1 ] , p [ 2 i + 1 ] ) p[2i]>max(p[2i−1],p[2i+1]) p[2i]>max(p[2i1],p[2i+1])
现在你需要计算,有几个长度为 n 的排列是强壮的,由于答案可能较大,你只需要输出答案对 998244353取模后的值

经过各种计算发现答案为 t a n ( x ) tan(x) tan(x)的生成函数第n项系数
可以用伯努利数计算这个值

#include 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i
#define ForD(i,n) for(int i=n;i>0;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (998244353)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector 
#define pi pair
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
	return x*f;
} 
#define MAXN (212345)
ll inj[MAXN],jie[MAXN];
void pre(int n) {
	jie[0]=1;For(i,n) jie[i]=mul(jie[i-1],i);
	inj[0]=inj[1]=1;Fork(i,2,n) inj[i]=(F-(F/i))*inj[F%i]%F;
	For(i,n) inj[i]=mul(inj[i],inj[i-1]);  
} 
ll p=F;
inline int pow2(int a,ll b)  //a^b mod p 
{  
    if (b==0) return 1%p;  
    int c=pow2(a,b/2);  
    c=(ll)c*c%p;  
    if (b&1) c=(ll)c*a%p;  	
    return c;  
}  
ll inv(ll a) { //gcd(a,p)=1
	return pow2(a,p-2);
}
#undef MAXN
namespace POLY{
	#define MAXN 262144
	const int MOD = 998244353, ROOT = 3;
	typedef vector<int> Poly;
	inline int add(int a, int b){ return (a + b) % MOD; }
	inline int sub(int a, int b){ return (a - b + MOD) % MOD; }
	inline int mul(int a, int b){ return (long long)a * b % MOD; }
	int power(int a, int b){
		int ret = 1;
		for (int t = a; b; b >>= 1){
			if (b & 1)ret = mul(ret, t);
			t = mul(t, t);
		}
		return ret;
	}
	int pow2(int n){
		int ret = 1;
		while (ret < n)ret *= 2;
		return ret;
	}
	void clean(Poly& p){
		while (!p.empty() && !p.back())p.pop_back();
	}
	Poly cut(const Poly& p, int n){
		return Poly(p.begin(), p.begin() + n);
	}
	Poly expand(const Poly& p, int n){
		Poly ret(n);
		copy(p.begin(), p.end(), ret.begin());
		return ret;
	}
	Poly operator + (Poly p, const Poly& p2){
		p.resize(max(p.size(), p2.size()));
		for (int i = 0; i < (int)p2.size(); i++)
			p[i] = add(p[i], p2[i]);
		return p;
	}
	Poly operator - (Poly p, const Poly& p2){
		p.resize(max(p.size(), p2.size()));
		for (int i = 0; i < (int)p2.size(); i++)
			p[i] = sub(p[i], p2[i]);
		return p;
	}
	Poly operator * (Poly p, int x)
	{
		for (int i = 0; i < (int)p.size(); i++)
			p[i] = mul(p[i], x);
		return p;
	}
	void dot(Poly& p, const Poly& p2){
		for (int i = 0; i < (int)p.size(); i++)
			p[i] = mul(p[i], p2[i]);
	}
	void fft(Poly& a, bool rev){
		static int g[MAXN + 1], w[MAXN] ;
		if (!g[0]){
			w[0] = 1;
			g[0] = 1; g[1] = power(ROOT, (MOD - 1) / MAXN);
			for (int i = 2; i < MAXN; i++)
				g[i] = mul(g[i - 1], g[1]);
		}
		int len = a.size(), d = MAXN / len;
		for (int i = 1, j = len / 2; i < len; i++){
			w[i] = g[d * (rev ? len - i : i)];
			if (i < j) swap(a[i], a[j]);
			for (int k = len; j < k; k >>= 1, j ^= k);
		}
		for (int s = 1; s < len; s <<= 1){
			int step = len / s / 2;
			for (int j = 0; j < len; j += 2 * s){
				for (int k = j, wk = 0; k < j + s; k++, wk += step){
					int t = mul(w[wk], a[k + s]);
					a[k + s] = sub(a[k], t); a[k] = add(a[k], t);
				}
			}
		}
		if (rev){
			int t = MOD / len; t = mul(t, t * len);
			for (int i = 0; i < len; i++)
				a[i] = mul(a[i], t);
		}
	}
	Poly operator * (const Poly& p1, const Poly& p2)
	{
		if (p1.empty() || p2.empty())return Poly();
		int len = pow2(p1.size() + p2.size());
		Poly p3 = expand(p1, len), p4 = expand(p2, len);
		fft(p3, 0); fft(p4, 0);
		dot(p3, p4); fft(p3, 1);
		p3.resize(p1.size() + p2.size() - 1);
		return p3;
	}
	Poly inv(const Poly& p)
	{
		int len = 2 * pow2(p.size());
		Poly a, b(len), exa = expand(p, len);
		b[0] = power(p[0], MOD - 2);
		for (int i = 4; i <= len; i *= 2){
			a = cut(exa, i / 2);
			a.resize(i); b.resize(i);
			fft(a, 0); fft(b, 0); dot(a, b);
			dot(b, Poly(i, 2) - a);
			fft(b, 1); b.resize(i / 2);
		}
		b.resize(p.size());
		return b;
	}
	
	int fact[MAXN], factInv[MAXN];
	void init()
	{
		fact[0] = 1;
		for (int i = 1; i < MAXN; i++)
			fact[i] = mul(fact[i - 1], i);
		factInv[MAXN - 1] = power(fact[MAXN - 1], MOD - 2);
		for (int i = MAXN - 1; i; i--)
			factInv[i - 1] = mul(factInv[i], i);
	}
	Poly bernoulli(int n)
	{
		Poly p(n + 1);
		for (int i = 0; i <= n; i++)
			p[i] = factInv[i + 1];
		return inv(p);
	}
}
//a(n) = abs[c(2*n-1)] where c(n)= 2^(n+1) * (1-2^(n+1)) * Ber(n+1)/(n+1)
int main()
{
//	freopen("B.in","r",stdin);
//	freopen(".out","w",stdout);
	pre(2e5+10);
	POLY::init();
	vi v=POLY::bernoulli(100010);
	int T=read();
	Rep(i,100010) v[i]=v[i]*(ll)jie[i]%F;
	while(T--) {
		ll n=read();n=(n+1)/2;n=n*2-1;
		ll t=pow2(2,n+1),t2=sub(1,pow2(2,n+1));
		ll t3=inv(n+1);
		ll t4=v[n+1];
		ll t5=t*t2%F*t3%F*t4%F;
		if((n+1)%4==0 ||n+1==1) t5=sub(F,t5); 
		if(n+1>=1) t5=sub(F,t5); 
		cout<<t5%F<<endl;
	}
	return 0;
}

你可能感兴趣的:(数位统计DP,比赛题解,多项式)