2021.6.13 考试解题报告
2021.6.13 考试解题报告
得分
| 题目 | 实际得分 | 期望得分|知识点|
|: ----😐:----😐:----😐:--😐
| \(\text{A}\) | 100 | 100|矩阵乘法|
|\(\text{B}\) | 0|0|排列组合,组合数学|
|\(\text{C}\)|60|40|缩点,树的直径,tarjan|
A
Description
\[\begin{aligned}
f(1) &= 1 \\
f(2) &= 1 \\
f(n) &= A \times f(n - 1) + B \times f(n - 2)
\end{aligned}
\]
求 \(f(n)\),\(1 \leq n \leq 2147483648\)。
Solution
写一个矩阵乘法,推出转移矩阵 :
\[\begin{bmatrix}
A & 1 \\
B & 0
\end{bmatrix}
\]
之后写一个矩阵快速幂就直接过了,记着开 \(\text{long long}\) 就行。
Code
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int mod = 7;
int a,b,n;
struct Matrix {
int z[5][5];
int n1,m1;
Matrix () {
memset(z,0,sizeof z);
n1 = m1 = 0;
}
} A , I , E;
inline int read()
{
int s = 0, f = 0;char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
Matrix operator * (const Matrix &m1,const Matrix &m2)
{
Matrix m3;
m3.m1 = m2.m1;
m3.n1 = m1.n1;
for(int i = 1;i <= m3.n1;i ++)
for(int k = 1;k <= m1.m1;k ++)
for(int j = 1;j <= m3.m1;j ++)
m3.z[i][j] += (m1.z[i][k] % mod) * (m2.z[k][j] % mod),
m3.z[i][j] >= mod ? m3.z[i][j] %= mod : m3.z[i][j];
return m3;
}
signed main()
{
//freopen("attack.in","r",stdin);
// freopen("attack.out","w",stdout);
a = read(),b = read(),n = read();
if(n == 1 || n == 2) {
cout << 1 << endl;
return 0;
}
I.n1 = I.m1 = 2;
I.z[1][1] = a,I.z[1][2] = 1;
I.z[2][1] = b,I.z[2][2] = 0;
A.n1 = 1,A.m1 = 2;
A.z[1][1] = 1,A.z[1][2] = 1;
E.n1 = E.m1 = 2;
for(int i = 1;i <= 2;i ++) E.z[i][i] = 1;
int nn = n - 2;
while(nn) {
if(nn & 1) E = E * I;
I = I * I;
nn >>= 1;
}
Matrix Ans = A * E;
Ans.z[1][1] %= mod;
printf("%lld\n",Ans.z[1][1]);
return 0;
}
B
Description
你有 \(n\) 个 1 和 \(m\) 个 0,组成一个排列,问有多大的概率使得这个从这个排列中任意一个位置向前 1 的个数大于等于 0 的个数。
Solution
这个菜鸡数学不好石锤了,这个题是一个结论题,某同学打了 3.6 kb 的表找出来了。
首先构建一个二维坐标系
C
Solution
先把同一个国家的人缩点,缩点后一棵树,之后在树上求出树的直径,找出树的直径的端点,分别从两个端点求一遍到所有点的距离,取一个最大值,输出答案即可。
因为根据 dfs 求树的直径的性质,所有的点肯定到树的直径的端点是最长的。
Code
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int Maxk = 5e5 + 10;
const int Maxn = 4e4 + 10;
int n,m,cnt,dd;
struct Node {
int to_;
int nex_;
int dis_;
}e[Maxk],E[Maxk];
int head[Maxn],head2[Maxn];
int dis[Maxn],Z[Maxn],val[Maxn];
int dfn[Maxn],low[Maxn],ret,t,kk;
int sta[Maxn],top,col[Maxn],res[Maxn];
bool f[Maxk],flag[Maxn];
inline int read()
{
int s = 0, f = 0;char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void add_edge(int from,int to,int dis)
{
e[++ cnt].to_ = to;
e[cnt].dis_ = dis;
e[cnt].nex_ = head[from];
head[from] = cnt;
}
void add(int from,int to,int dis)
{
E[++ cnt].to_ = to;
E[cnt].dis_ = dis;
E[cnt].nex_ = head2[from];
head2[from] = cnt;
}
void tarjan(int s,int fa)
{
dfn[s] = low[s] = ++ ret;
sta[++ top] = s;//加入点
f[s] = true;
for(int i = head[s];i;i = e[i].nex_) {
int y = e[i].to_;
if(y == fa) continue;
if(!dfn[y]) {
tarjan(y,s);
low[s] = min(low[s],low[y]);
}
else if (f[y]) {
low[s] = min(low[s],dfn[y]);
}
}
if(low[s] == dfn[s]) {
t ++;
do {
col[sta[top]] = t;
res[t] ++;
f[sta[top]] = false;
top -- ;
}while(s != sta[top + 1]);
}
}
void dfs(int s,int sum,int fa)
{
dis[s] = sum;
for(int i = head2[s];i;i = E[i].nex_) {
int y = E[i].to_;
if(y == fa) continue;
dfs(y,sum + E[i].dis_,s);
}
}
signed main()
{
//freopen("QAQ.in","r",stdin);
//freopen("prize.out","w",stdout);
n = read(),m = read();
for(int i = 1;i <= m;i ++) {
int x = read(),y = read(),z = read();
add_edge(x,y,z);
add_edge(y,x,z);
}
for(int i = 1;i <= n;i ++) {
if(!dfn[i]) tarjan(i,0);
}
cnt = 0;
for(int i = 1;i <= n;i ++) {
for(int j = head[i];j;j = e[j].nex_) {
if(col[i] != col[e[j].to_]) {
add(col[i],col[e[j].to_],e[j].dis_);
}
}
}
memset(dis,0x3f,sizeof dis);
dfs(1,0,0);
int Max = 0,iddd = 1,idd = 1;
for(int i = 1;i <= t;i ++) {
if(dis[i] == 0x3f3f3f3f) continue;
if(Max < dis[i])
Max = dis[i],iddd = i;
}
memset(dis,0x3f,sizeof dis);
dfs(iddd,0,0);
Max = 0;
for(int i = 1;i <= t;i ++) {
if(dis[i] != 0x3f3f3f3f)
if(Max < dis[i])
Max = dis[i],idd = i;
val[i] = dis[i];
}
memset(dis,0x3f,sizeof dis);
dfs(idd,0,0);
for(int i = 1;i <= t;i ++) {
if(val[i] == 0x3f3f3f3f || dis[i] == 0x3f3f3f3f) continue;
dis[i] = max(dis[i],val[i]);
Z[i] = dis[i];
}
for(int i = 1;i <= n;i ++) {
printf("%d\n",Z[col[i]]);
}
return 0;
}