正睿 2025 NOIP 20连测 Day11
T1
泠珞获得了图灵奖! 她的最新研究可以在多项式时间内求出一张无向图的哈密顿回路个数。
一个 \(n\) 个点 \(m\) 条边的简单无向图 \(G = (V, E)\), 点集为 \(V = \{1, 2, \dots, n\}\), \(E = \{(u_1, v_1), (u_2, v_2), \dots, (u_m, v_m)\}\), 无重边无自环
一条哈密顿回路为一个长度为 \(n\) 的排列 \(p_1, p_2, \dots, p_n\), 满足:
- \(1 \leq p_i \leq n\)
- \(\forall i < j, p_i \neq p_j\)
- \(\forall i = 1, 2, \dots, n, p_i\) 和 \(p_{i \pmod{n} + 1}\) 之间有边相连。
如果两个排列 \(p, q\) 可以通过循环位移得到, 那么我们认为这是同一条哈密顿回路。
研究了泠珞的科技之后, 你灵机一动! 发现自己可以求出所有 \(n\) 个点 \(m\) 条边的简单无向图的哈密顿回路个数之和!
于是你需要写一个程序解决这个问题, 由于答案可能很大, 请输出答案对 \(10^9 + 7\) 取模的结果。
考虑对于一个确定的排列 \(p\),有多少个图满足 \(p\) 是一个哈密顿回路。
考虑容斥,钦定排列中有 \(i\) 条边存在,设 \(N=\frac{(n-1)\times n}{2}\) 即答案等于
外星科技化简一下,即为 \((n-1)!\times {N-n\choose m-n}\)。
我这里傻逼了,用 lucas 算这个组合数,,实际上只需要下降幂,即考虑到 \({N-n\choose m-n} = \frac{(N-n)!}{(m-n)!(N-m)!}=(N-n)\times (N-n-1)\times \cdots \times (N-m+1)\times \frac{1}{(m-n)!}\)。
const int MAXN = 1e7 + 5, mod = 1e9 + 7, S = 1e7;
const int fac1e7[] = {1, 682498929, 491101308, 76479948, 723816384, 67347853, 27368307, 625544428, 199888908, 888050723, 927880474, 281863274, 661224977, 623534362, 970055531, 261384175, 195888993, 66404266, 547665832, 109838563, 933245637, 724691727, 368925948, 268838846, 136026497, 112390913, 135498044, 217544623, 419363534, 500780548, 668123525, 128487469, 30977140, 522049725, 309058615, 386027524, 189239124, 148528617, 940567523, 917084264, 429277690, 996164327, 358655417, 568392357, 780072518, 462639908, 275105629, 909210595, 99199382, 703397904, 733333339, 97830135, 608823837, 256141983, 141827977, 696628828, 637939935, 811575797, 848924691, 131772368, 724464507, 272814771, 326159309, 456152084, 903466878, 92255682, 769795511, 373745190, 606241871, 825871994, 957939114, 435887178, 852304035, 663307737, 375297772, 217598709, 624148346, 671734977, 624500515, 748510389, 203191898, 423951674, 629786193, 672850561, 814362881, 823845496, 116667533, 256473217, 627655552, 245795606, 586445753, 172114298, 193781724, 778983779, 83868974, 315103615, 965785236, 492741665, 377329025, 847549272, 698611116};
int n, m, N;
int quickpow(int a, int b) {
int ret = 1;
while (b) {
if (b & 1) ret = ret * a % mod;
a = a * a % mod; b >>= 1;
}
return ret;
}
int facg(int x) {
if (x >= mod) return 0ll;
int f = fac1e7[x / S];
for (int i = (x / S) * S + 1; i <= x; ++i)
f = f * i % mod;
return f;
}
int ifacg(int x) {
int f = facg(x);
if (f == 0) return 0;
return quickpow(f, mod - 2);
}
int lucas(int n, int m) {
if (n < m) return 0;
if (n < mod && m < mod) return facg(n) * ifacg(m) % mod * ifacg(n - m) % mod;
return lucas(n / mod, m / mod) * lucas(n % mod, m % mod) % mod;
}
void work() {
cin >> n >> m;
N = (n - 1) * n / 2;
cout << facg(n - 1) * lucas(N - n, m - n) % mod << endl;
}
/*
N = (n - 1) * n / 2
(n - 1)! * (sum_{i=0}^n (-1)^i*C(N-i,m)*C(n,i))
= (n-1)! * C(N-n, m-n)
*/
T2. Revealed
放个官方题解。
首先我们的策略大概是,要么向右扩张,或者在经过某个颜色最后一次出现的位置时候把这个颜色之前的所有出现位置都改了。
所以可以说明等价于找到一条从 \((1,1)\) 走到 \((1,n)\) 或者 \((2,n)\) 的简单路径,路径上相邻两个格子如果颜色不同就会花费 \(1\) 的代价,并且如果路径之外有某种颜色最后一次出现的位置,还需要花费 \(1\) 的代价变了它。
那么就可以直接 dp 了,设 \(f_{1/2,i}\) 表示走到了 \((1,i)/(2,i)\) 的最小代价,转移可以参考下面的:
for(int i=1;i<=n;i++)
{
int w0=f[i-1][0]+(a[i-1][0]!=a[i][0]);
int w1=f[i-1][1]+(a[i-1][1]!=a[i][1]);
f[i][0]=min(w0+(vis[i][1]&&a[i][0]!=a[i][1]),w1+(a[i][0]!=a[i][1]));
f[i][1]=min(w1+(vis[i][0]&&a[i][0]!=a[i][1]),w0+(a[i][0]!=a[i][1]));
}
其中 \(vis\) 表示该格子是否是该颜色最后一次出现。
T3. Jealousy
首先一个区间合法,当且仅当,每个数字都至少存在一个质因子 \(p\),使得其在 \(p\) 上的指数严格大于其余数字在 \(p\) 上的指数。
注意到如果 \([l, r]\) 合法,那么 \([l, r]\) 的所有子区间都合法,因此我们可以对于每个 \(r\) 求出合法的最小的一个 \([l,r]\),双指针扫一遍,只需要快速维护一个区间是否合法。
实际上也只需要对于每个数字,插入或者删除的时候遍历它的每个质因子,维护一下该质因子指数最大的数即可。
因为指数很小所以可以直接暴力或者 set,时间复杂度 \(O(n \log^2 V)\)。

浙公网安备 33010602011771号