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;
}
posted @ 2021-06-14 10:49  Ti_Despairy  阅读(70)  评论(0)    收藏  举报