2022.9.15———HZOI【CSP-S开小灶4】游寄
Preface
\(Rank31/39\)
\(20pts + 0pts = 20pts\)
最近出现了暴力不会打的情况
我震惊
我tm暴力不会打?
然后其实仔细思考也是可以打的。只要暴力不是\(dp\)。但是赛时我老是懒。。。
T1 山洞,T2 beauty
\(\mathfrak{T1}\ 山洞\)
\(Ayaka\)讲的,我竟然听懂了
首先考虑这样一个事情,走长度为\(1\)和走长度为\(n+1\)长是否等同?
答案是显然等同。因为要对\(n\)取模,这是个环好吧。
再思考,假设我从\(x\)位置走\(a\)长度到\(y\)位置,然后再从\(y\)走\(b\)长度到\(x\)位置,从\(x\)走到\(x\)方案数是不是要加上第一个过程的方案数\(\times\)第二个过程的方案数?
这就有点神奇了
我谔谔。
仔细一想,他为什么不对呢?
第一个过程和第二个过程有冲突吗?没有。
因此他满足乘法原理。
做一件事,完成它需要分成\(n\)个步骤,做第一 步有\(m1\)种不同的方法,做第二步有\(m2\)种不同的方法,……,做第\(n\)步有\(mn\)种不同的方法。那么完成这件事共有 \(N=m1×m2×m3×…×mn\) 种不同的方法。 和加法原理是数学概率方面的基本原理。———度娘
当\(A\)与\(B\)独立时,乘法原理适用。———\(me\)
然后思路就比较明确了,首先处理出前\(n\)次的\(dp\),然后用\(f[n][i]\)去转移,注意是第\(n\)项,然后用\(n\)去转移\(2n\)等等,二进制拆分指数,矩阵快速幂即可(矩阵快速幂第\(n\)项)。
然后最后可能会有剩余,因为\(m\)不一定被\(n\)整除,此时最后还需要暴力dp一下。
T1
#include <iostream>
#include <cstring>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define MARK cout << "###"
#define MARKER "@@@"
#define LMARK "!!!~~~"
#define ZY " qwq "
#define _ ' '
#define Endl cout << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 1005
#define M 1000000002
#define mod %
#define P 1000000007
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL), cerr.tie(NULL);}
/*
Ayaka确实强
处理出来走前n步的方案都是些啥
考虑这个
设两个数组都是走x步的(其实是同一个数组),那么:走2x步到位置place 就等同于 先走x步到另一个位置 再走x步到达位置place
所以就可以枚举这个走x步的时候,第一个数组所在位置,第二个数组所在位置,然后直接相乘转移到2x步的位置(乘法原理)
然后就可以跑矩阵快速幂了,m/n
因为走n+1步就等同于走1步,所以就可以先预处理f[n][n],不过矩阵快速幂的时候只会用上f[n][1~n]
最后因为n不一定整除m,所以最后要再暴力dp一下,也就是f[floor(m/n)*n] * f[m%n] -> f[m]
*/
int n, m;
long long a[N], tmp[N], res[N];
long long f[N][N];
/*
inline long long ksm(long long A, long long B){// normal
long long res(1);
while (B != 0){
if ((B & 1) == 1) res = res * A mod P;
A = A * A mod P;
B >>= 1;
}
return res;
}
*/
inline void workres(){
memset(tmp, 0, sizeof(tmp));
for (re i = 0 ; i < n ; ++ i)
for (re j = 0 ; j < n ; ++ j)// 两个n合成一个2n
tmp[(i+j) mod n] = (tmp[(i+j) mod n] + res[i] * a[j] mod P) mod P;
for (re i = 0 ; i < n ; ++ i)
res[i] = tmp[i];
}
inline void worka(){
memset(tmp, 0, sizeof(tmp));
for (re i = 0 ; i < n ; ++ i)
for (re j = 0 ; j < n ; ++ j)
tmp[(i+j) mod n] = (tmp[(i+j) mod n] + a[i] * a[j] mod P) mod P;
for (re i = 0 ; i < n ; ++ i)
a[i] = tmp[i];
}
inline void ksm(long long B){
while (B != 0){
if ((B & 1) == 1) workres();
worka();
B >>= 1;
}
}
void work(){
cin >> n >> m;
f[1][1] = f[1][n-1] = 1;// 从0往右、往左
for (re i = 2 ; i <= n ; ++ i){
for (re j = 0 ; j < n ; ++ j){
if ((j-i+n) mod n != (j+i) mod n)// 我超!去重!我说我大样例咋没过嘞
f[i][j] = (f[i-1][(j-i+n) mod n] + f[i-1][(j+i) mod n]) mod P;
else
f[i][j] = f[i-1][(j+i) mod n];
}
}
for (re i = 0 ; i < n ; ++ i)
a[i] = f[n][i];
res[0] = 1;// 相当于直接把a转移过来
ksm(m/n); m %= n;
if (m != 0){
for (re i = 0 ; i < n ; ++ i)
a[i] = f[m][i];
workres();
}
cout << res[0] << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
\(\mathfrak{T2}\ beauty\)
树的重心弔题
好像是某种构造,我没学
T2
#include <iostream>
#define GMY (520&1314)
#define FBI_OPENTHEDOOR(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout);
#define re register int
#define char_phi signed
#define MARK cout << "###"
#define MARKER "@@@"
#define LMARK "!!!~~~"
#define ZY " qwq "
#define _ ' '
#define Endl cout << '\n'
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define N 100005
#define KKK 30005
using namespace std;
inline void Fastio_setup(){ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL), cerr.tie(NULL);}
int n, K, whatsthis, star_cnt, final_ans;
char is[N];
int head[N], sz[N];
struct star{int v, nxt;} e[N<<1];
inline void star_add(int u, int v){e[++ star_cnt].v=v, e[star_cnt].nxt=head[u], head[u]=star_cnt;}
void dfs(int x, int faer){
if (is[x] == true)
sz[x] = 1;
for (re i = head[x] ; i ; i = e[i].nxt){
int v = e[i].v;
if (v == faer)
continue;
dfs(v, x);
sz[x] += sz[v];
final_ans += MIN(sz[v], K - sz[v]);
}
}
void work(){
cin >> n >> K >> whatsthis; K *= 2;
for (re i = 1, who ; i <= K ; ++ i)
{cin >> who; is[who] = true;}
for (re i = 1, uu, vv ; i <= n-1 ; ++ i)
{cin >> uu >> vv; star_add(uu, vv), star_add(vv, uu);}
dfs(1, 0);
cout << final_ans << '\n';
}
// #define IXINGMY
char_phi main(){
#ifdef IXINGMY
FBI_OPENTHEDOOR(a);
#endif
Fastio_setup();
work();
return GMY;
}
$$\huge{\mathcal{Here\ We\ Are,\ Nick\ Of\ Time\ !}}$$