The 4th Universal Cup GP of Kyoto, April 4-5, 2026 题解

G. The Symbolic Tree

一棵拥有 n 个顶点的有根树。树根为顶点 1,

根节点上写的整数是 K。

对于除根节点以外的每个顶点,该顶点上写的整数不大于其父节点上写的正整数。

求在树的顶点上写整数的所有可能方案数对 998244353 取模后的余数。

当且仅当存在某个顶点,其上写的整数在两种方案中不同时,这两种写整数的方案被视为不同。

n≤3000,k≤1e9n\le 3000 ,k\le 1e9n≤3000,k≤1e9

先计算出k≤nk\le nk≤n 的答案,然后用拉格朗日推导后面的

cpp 复制代码
#include<bits/stdc++.h> 
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<n;i++)
#define ForD(i,n) for(int i=n;i;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<int> 
#define pi pair<int,int>
#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<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<<a[i][j]<<' ';\
						cout<<a[i][m]<<endl; \
						} 
#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);
#define sqr(x) (x*x)
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;}
ll gcd(ll a,ll b){return (!a)?b:a%b;}
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;
} 

template<int MOD, int RT> struct mint {
	static const int mod = MOD;
	static constexpr mint rt() { return RT; } // primitive root for FFT
	int v; explicit operator int() const { return v; } // explicit -> don't silently convert to int
	mint():v(0) {}
	mint(ll _v) { v = int((-MOD < _v && _v < MOD) ? _v : _v % MOD);
		if (v < 0) v += MOD; }
	bool operator==(const mint& o) const {
		return v == o.v; }
	friend bool operator!=(const mint& a, const mint& b) { 
		return !(a == b); }
	friend bool operator<(const mint& a, const mint& b) { 
		return a.v < b.v; }
   
	mint& operator+=(const mint& o) { 
		if ((v += o.v) >= MOD) v -= MOD; 
		return *this; }
	mint& operator-=(const mint& o) { 
		if ((v -= o.v) < 0) v += MOD; 
		return *this; }
	mint& operator*=(const mint& o) { 
		v = int((ll)v*o.v%MOD); return *this; }
	mint& operator/=(const mint& o) { return (*this) *= inv(o); }
	friend mint pow(mint a, ll p) {
		mint ans = 1; assert(p >= 0);
		for (; p; p /= 2, a *= a) if (p&1) ans *= a;
		return ans; }
	friend mint inv(const mint& a) { assert(a.v != 0); 
		return pow(a,MOD-2); }
//	mint inv() { assert(v != 0); 
//		return pow(v,MOD-2); }
	mint operator-() const { return mint(-v); }
	mint& operator++() { return *this += 1; }
	mint& operator--() { return *this -= 1; }
	friend mint operator+(mint a, const mint& b) { return a += b; }
	friend mint operator-(mint a, const mint& b) { return a -= b; }
	friend mint operator*(mint a, const mint& b) { return a *= b; }
	friend mint operator/(mint a, const mint& b) { return a /= b; }
};
const int MOD=998244353; 
using mi = mint<MOD,5>; // 5 is primitive root for both common mods

int n;
#define MAXN (3010)
mi f[MAXN][MAXN]={},s[MAXN][MAXN]={};
vector<int> v[MAXN];

void dfs(int x,int fa) {
    bool is_leaf=true;
	for (auto u:v[x])
		if (u!=fa) {
            is_leaf=false;
			dfs(u,x);
		}
    if (is_leaf) {
        For(i,n) f[x][i]=1,s[x][i]=i;
    }else{
         For(i,n){
             mi pord=1;
             for(auto u:v[x]){
                 if (u==fa) continue;
                 pord*=s[u][i];
             }
             f[x][i]=pord;
             s[x][i]=s[x][i-1]+f[x][i];
         }
    }
}

mi lagrange_prediction(vector<mi> y, long long k) {
    int n = y.size() - 1;  
    if (k <= n) return y[k];
    
    mi ans = 0;
    for (int i = 0; i <= n; i++) {
        mi num = 1, den = 1;
        for (int j = 0; j <= n; j++) {
            if (j == i) continue;
            num = num * (k - j);
            den = den * (i - j);
        }
        ans = ans + y[i] * num / den;
    }
    return ans;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;ll m;cin>>m;

     For(i,n-1) {
     	int x,y;
     	cin>>x>>y;
         v[x].pb(y); v[y].pb(x);
     }

     dfs(1,-1);

     if(m+1<=n)
	     cout<<f[1][m+1].v<<endl;
	else {
		vector<mi> vec(n);
		For(i,n) vec[i-1]=f[1][i];
		cout<<lagrange_prediction(vec,m).v<<endl;
	}
}

L. Make Many KUPC

给定一个长度为 n 的字符串 S,由大写英文字母组成。你可以对

执行任意次数以下操作:

选择一个四元组整数 (i,j,k,l)

,满足 SiSjSkSl=="KUPC"S_iS_jS_kS_l=="KUPC"SiSjSkSl=="KUPC"

将它们 全部替换为X,并获得i∗j∗k∗li*j*k*li∗j∗k∗l 日元的收益。

求总共能获得的最大收益,结果对 998244353 取模。

cpp 复制代码
#include<bits/stdc++.h> 
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<n;i++)
#define ForD(i,n) for(int i=n;i;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<int> 
#define pi pair<int,int>
#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<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<<a[i][j]<<' ';\
						cout<<a[i][m]<<endl; \
						} 
#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);
#define sqr(x) (x*x)
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;}
ll gcd(ll a,ll b){return (!a)?b:a%b;}
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;
} 

template<int MOD, int RT> struct mint {
	static const int mod = MOD;
	static constexpr mint rt() { return RT; } // primitive root for FFT
	int v; explicit operator int() const { return v; } // explicit -> don't silently convert to int
	mint():v(0) {}
	mint(ll _v) { v = int((-MOD < _v && _v < MOD) ? _v : _v % MOD);
		if (v < 0) v += MOD; }
	bool operator==(const mint& o) const {
		return v == o.v; }
	friend bool operator!=(const mint& a, const mint& b) { 
		return !(a == b); }
	friend bool operator<(const mint& a, const mint& b) { 
		return a.v < b.v; }
   
	mint& operator+=(const mint& o) { 
		if ((v += o.v) >= MOD) v -= MOD; 
		return *this; }
	mint& operator-=(const mint& o) { 
		if ((v -= o.v) < 0) v += MOD; 
		return *this; }
	mint& operator*=(const mint& o) { 
		v = int((ll)v*o.v%MOD); return *this; }
	mint& operator/=(const mint& o) { return (*this) *= inv(o); }
	friend mint pow(mint a, ll p) {
		mint ans = 1; assert(p >= 0);
		for (; p; p /= 2, a *= a) if (p&1) ans *= a;
		return ans; }
	friend mint inv(const mint& a) { assert(a.v != 0); 
		return pow(a,MOD-2); }
		
	mint operator-() const { return mint(-v); }
	mint& operator++() { return *this += 1; }
	mint& operator--() { return *this -= 1; }
	friend mint operator+(mint a, const mint& b) { return a += b; }
	friend mint operator-(mint a, const mint& b) { return a -= b; }
	friend mint operator*(mint a, const mint& b) { return a *= b; }
	friend mint operator/(mint a, const mint& b) { return a /= b; }
};
const int MOD=998244353; 
using mi = mint<MOD,5>; // 5 is primitive root for both common mods

namespace simp {
	vector<mi> fac,ifac,invn;
	void check(int x) {
		if (fac.empty()) {
			fac={mi(1),mi(1)};
			ifac={mi(1),mi(1)};
			invn={mi(0),mi(1)};
		}
		while (SI(fac)<=x) {
			int n=SI(fac),m=SI(fac)*2;
			fac.resize(m);
			ifac.resize(m);
			invn.resize(m);
			for (int i=n;i<m;i++) {
				fac[i]=fac[i-1]*mi(i);
				invn[i]=mi(MOD-MOD/i)*invn[MOD%i];
				ifac[i]=ifac[i-1]*invn[i];
			}
		}
	}
	mi gfac(int x) {
		assert(x>=0);
		check(x); return fac[x];
	}
	mi ginv(int x) {
		assert(x>0);
		check(x); return invn[x];
	}
	mi gifac(int x) {
		assert(x>=0);
		check(x); return ifac[x];
	}
	mi binom(int n,int m) {
		if (m < 0 || m > n) return mi(0);
		return gfac(n)*gifac(m)*gifac(n - m);
	}
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n;
	cin>>n;
	string s;
	cin>>s;
	set<int> S[26];
	Rep(i,n) {
		S[s[i]-'A'].insert(i+1);
	}
	ll ans=0;
	while(1) {
		auto it4=S['C'-'A'].end();
		if(it4==S['C'-'A'].begin()) break;
		it4--;
		ll t4=*it4;
		auto it3=S['P'-'A'].upper_bound(t4);
		if(it3==S['P'-'A'].begin()) break;
		it3--;
		ll t3=*it3;
		auto it2=S['U'-'A'].upper_bound(t3);
		if(it2==S['U'-'A'].begin()) break;
		it2--;
		ll t2=*it2;
		auto it1=S['K'-'A'].upper_bound(t2);
		if(it1==S['K'-'A'].begin()) break;
		it1--;
		ll t1=*it1;
		ans+=(t1)*(t2)%F*(t3)%F*(t4);
		ans%=998244353;
		S['K'-'A'].erase(t1);
		S['U'-'A'].erase(t2);
		S['P'-'A'].erase(t3);
		S['C'-'A'].erase(t4);
	}
	cout<<ans;
	return 0;
}

O Xor Triangle

求满足 1≤a,b<2n1 \le a,b \lt 2^n1≤a,b<2n 且满足以下条件的整数对 (a,b)(a,b)(a,b)

的数量,结果对质数 998244353 取模。

存在一个以 a,b,a xor b 为边长的非退化三角形。

oeis

cpp 复制代码
#include<bits/stdc++.h> 
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<n;i++)
#define ForD(i,n) for(int i=n;i;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<int> 
#define pi pair<int,int>
#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<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<<a[i][j]<<' ';\
						cout<<a[i][m]<<endl; \
						} 
#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);
#define sqr(x) (x*x)
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;}
ll gcd(ll a,ll b){return (!a)?b:a%b;}
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;
} 
//4**(n-1) - 3*3**(n-1) + 3*2**(n-1) - 1)

template<int MOD, int RT> struct mint {
	static const int mod = MOD;
	static constexpr mint rt() { return RT; } // primitive root for FFT
	int v; explicit operator int() const { return v; } // explicit -> don't silently convert to int
	mint():v(0) {}
	mint(ll _v) { v = int((-MOD < _v && _v < MOD) ? _v : _v % MOD);
		if (v < 0) v += MOD; }
	bool operator==(const mint& o) const {
		return v == o.v; }
	friend bool operator!=(const mint& a, const mint& b) { 
		return !(a == b); }
	friend bool operator<(const mint& a, const mint& b) { 
		return a.v < b.v; }
   
	mint& operator+=(const mint& o) { 
		if ((v += o.v) >= MOD) v -= MOD; 
		return *this; }
	mint& operator-=(const mint& o) { 
		if ((v -= o.v) < 0) v += MOD; 
		return *this; }
	mint& operator*=(const mint& o) { 
		v = int((ll)v*o.v%MOD); return *this; }
	mint& operator/=(const mint& o) { return (*this) *= inv(o); }
	friend mint pow(mint a, ll p) {
		mint ans = 1; assert(p >= 0);
		for (; p; p /= 2, a *= a) if (p&1) ans *= a;
		return ans; }
	friend mint inv(const mint& a) { assert(a.v != 0); 
		return pow(a,MOD-2); }
		
	mint operator-() const { return mint(-v); }
	mint& operator++() { return *this += 1; }
	mint& operator--() { return *this -= 1; }
	friend mint operator+(mint a, const mint& b) { return a += b; }
	friend mint operator-(mint a, const mint& b) { return a -= b; }
	friend mint operator*(mint a, const mint& b) { return a *= b; }
	friend mint operator/(mint a, const mint& b) { return a /= b; }
};
const int MOD=998244353; 
using mi = mint<MOD,5>; // 5 is primitive root for both common mods

namespace simp {
	vector<mi> fac,ifac,invn;
	void check(int x) {
		if (fac.empty()) {
			fac={mi(1),mi(1)};
			ifac={mi(1),mi(1)};
			invn={mi(0),mi(1)};
		}
		while (SI(fac)<=x) {
			int n=SI(fac),m=SI(fac)*2;
			fac.resize(m);
			ifac.resize(m);
			invn.resize(m);
			for (int i=n;i<m;i++) {
				fac[i]=fac[i-1]*mi(i);
				invn[i]=mi(MOD-MOD/i)*invn[MOD%i];
				ifac[i]=ifac[i-1]*invn[i];
			}
		}
	}
	mi gfac(int x) {
		assert(x>=0);
		check(x); return fac[x];
	}
	mi ginv(int x) {
		assert(x>0);
		check(x); return invn[x];
	}
	mi gifac(int x) {
		assert(x>=0);
		check(x); return ifac[x];
	}
	mi binom(int n,int m) {
		if (m < 0 || m > n) return mi(0);
		return gfac(n)*gifac(m)*gifac(n - m);
	}
}
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	// int n=read();
	// int S=1<<n;
	// int t=0;
	// For(i,S-1) For(j,S-1) {
		// int k=i^j;
		// if(i+j>k && i+k>j && j+k>i) {
			// ++t;
		// }
	// }
	// cout<<t;
	ll n;cin>>n;++n;
	cout<<(pow((mi)4,(n-1)) - (mi)3*pow((mi)3,n-1) + 3*pow((mi)2,n-1) - (mi)1).v;
	return 0;
}
相关推荐
澈2072 小时前
高效查找算法详解:从顺序到哈希
数据结构·算法·哈希算法
kobesdu2 小时前
开源3D激光SLAM算法的异同点、优劣势与适配场景总结
算法·3d·机器人·ros
ZC跨境爬虫3 小时前
3D 地球卫星轨道可视化平台开发 Day13(卫星可视化交互优化+丝滑悬停聚焦)
前端·算法·3d·json·交互
水木流年追梦3 小时前
CodeTop Top 100 热门题目(按题型分类)
算法·leetcode
Tisfy3 小时前
LeetCode 1722.执行交换操作后的最小汉明距离:连通图
算法·leetcode·dfs·题解·深度优先搜索·连通图
不知名的老吴3 小时前
案例教学:最长递增子序列问题
数据结构·算法·动态规划
样例过了就是过了3 小时前
LeetCode热题100 杨辉三角
c++·算法·leetcode·动态规划
念越3 小时前
算法每日一题 Day05|双指针解决盛最多水的容器问题
算法·力扣
eggrall3 小时前
Leetcode 最大连续 1 的个数 III(medium)
算法·leetcode·职场和发展