2019.11.9 , 2019.11.10 题解报告


2019.11.9 , 2019.11.10 题解报告

\[一个人的力量是微小的 , 一个机房的人的力量是撼天动地的\]
\[\text{By:Unluckyblock}\]

答题情况:

  • 总成绩 : 360, 排名 : ? / ?
    Day1 : T1 : 100 T2 : 50 T3 : 40 总成绩 : 190 , 排名: 34 / 115
    Day2 : T1 : 100 T2 : 40 T3 : 30 总成绩 : 170 , 排名: 19 / 132

各题目分析:

Day 1 :

  • 题目1:
    预估成绩 : 100 实际成绩 : 100 考试用时 : 7 : 50 ~ 8 : 40

    刚开考思路比较清晰 , 直接想到了标算 , 标算不难打 , 很快实现 .
    之后一直手造数据 卡自己的程序 , 对程序进行了调整 , 保证了正确性

  • 题目2 :
    预估成绩 : 50 实际成绩 : 50 考试用时 : 8 : 40 ~ 9 : 30 , 9 : 40 ~ 10 : 40

    先写了dfs暴力 , 造数据验证了正确性
    之后发现了一些优美的性质 , 考虑标算 , 但是并没有做出来
    拿到了dfs的保底分

  • 题目3:
    预估成绩 : 40 实际成绩 : 40 考试用时 : 9 :30 ~9 : 40

    发现T3 部分分与 T1神似 , 于是把T1粘了过来 , 并进行了调整
    造数据验证了正确性

    后来觉得T2 比 T3更简单一些 , 就去继续推T2

Day 2 :

  • 题目1:
    预估成绩 : 100 实际成绩 : 100 考试用时 : 8 : 00 ~ 9 : 03

    先手推式子 找规律 , 发现可以进行DP , 手推多组数据 验证了DP的正确性
    观察状态转移方程 , 可以矩阵优化 , 很快写完

  • 题目2:
    预估成绩 : 40 实际成绩 : 40 考试用时 : 9 : 50 ~ 11 : 00

    先手推各性质 , 发现了 只会使用一个二元组的性质
    但是并没有想到 背包的做法 , 于是打了暴力 DFS

  • 题目3:
    预估成绩 : 40 实际成绩 : 30 考试用时 : 9 : 10 ~ 9 : 44

    觉得T3比 T2更可做一些 , 就先来看T3
    并不会 正解的 弦图最小染色 , 于是先打了暴力30分
    觉得另外 10分的暴力比较可拿 , 但是由于对 "树链"的概念认识不清, 没有拿到 相应分数


题目解析:

Day1 :

T1:

按照三元组中不同点的数量进行讨论:

  1. 三元组中 点都相同, 即(i, i, i), 此类有N个
  2. 三元组中 两点相同, 即(i, i, j),
    则三元组两点间距离都为 0
    处理出 与任意一点 距离为0的点的数量即可

  3. 三元组中 三点都不同
    有两种情况:
  4. 一点 在其中两点的路径上
    显然, 对于此类情况, 三点之间的距离只能都为0

  5. 一点 不在其中两点的路径上
    对于此类情况, 必然存在一个点, 到达三点之间的距离相同
    但是 被选择的三点距离一定都为 0
    情况2 会被情况1 包括, 故不须额外计算

由于是一棵树, 可以直接使用bfs O(n) 求得单源最短路
在bfs时处理出第2, 3种点对即可

一共需要进行n次 bfs , 总复杂度O(n ^ 2)


T2:

题目要求[1,k]内所有房间都能走到1号房间,[k + 1,n]内都走不到1号房间
则 [1, k] 内所有房间 都不能走到 [k + 1, n]内
同理, [k + n] 内所有房间 都不能走到 [1, k]内
即: p[1] ~ p[k] 值域为 [1,k] , p[k + 1] ~ p[n] 值域为 [k + 1, n]

对于 p[k + 1] ~ p[n], 可以在 [k + 1, n] 内随意选择,
则方案数有 : (N - K) ^ (N - K)种

对于 p[1] ~ p[k], 要保证经过转化后, p[i] 都可以变为1
将转化过程进行 转化, 从图的角度进行考虑:
给定k个结点, 每一个结点可以向 1 ~ k中任意一结点连一条有向边
使所有点都能到达 结点1 , 求连边方案数

显然, 合法图中 存在且只存在 一个环 :
因为每个点只有一条出边, 则若环中没有1, 则不合法
由于1 也有一条出边, 可连向 [1, K] 任意一点, 则必然构成一个环
对于一个合法图, 若删除结点1的出边,图一定变为 一棵树
则题目变为: 求有k个点的带标号树 的数量

由于一个prufer序列 只唯一对应 一棵带标号树
则 有k个点的带标号树 的数量 等于 k个节点的树 组成的prufer序列的数量
k个节点的树 组成的prufer序列长度为 k - 2, 各位可任意选择[1,k], 则方案数为 : k ^ (k - 2)
再考虑被删去的 1的出边, 可以在[1, k]之间任意选择, 故总方案数为 : k ^ (k - 1)

综上, 总方案数为 : k ^ (k - 1) * (N - K) ^ (N - K)


T3:

40%数据 :
做法与Day1 T1类似

预处理出 每一个结点 与其距离为 奇数/ 偶数的点
每次询问枚举合适的点, 求和求逆元即可
模数为 1e9 + 7, 可费马小定理求逆元
总复杂度O(n ^ 2 + nmlogk)

100 % 数据:

有二非常显然非常zz的结论 :

  1. 对于一个结点 , 其他节点只能位于 其子树内 / 其子树外
  2. 对于一条链上 三点之间的距离关系 :
    1. 若1, 2 距离为 偶数 , 2, 3距离为偶数 , 则1 , 3距离为 偶数
    2. 若1, 2 距离为 偶数 , 2, 3距离为奇数 , 则1 , 3距离为 奇数

显然, 可以通过树形DP先处理 每一节点子树内 距离奇数 / 偶数点 的数量 ,
再通过每一个点的 父亲结点 ,更新 每一节点子树外 距离奇数 / 偶数点 的数量 .

根据当前边的奇偶性选择从另外一个点的奇数的答案转移过来还是偶数的答案转移过来。
具体的讲,用f[i][0]表示与i距离为偶数的点的数量,f[i][1]表示与i距离为奇数的点数量,当u从v转移且u和v之间的边为偶数时。f[u][0]从f[v][0]转移过来。如果该边为奇数,那么f[u][0]从f[v][1]转移过来。

第一遍dfs统计子树内造成的贡献, 第二遍dfs统计子树外造成的贡献.


Day2 :

T1:

显然 不论合法, 总方案数为: (N - 1) ^ k (因为每一头猪传球时只有N - 1种传法)
则只需要求得 传回发球者的方案数即可

  1. 矩阵优化DP :

    发现 传球只有两种结果 :
    1. 传给发球者
    2. 不传给发球者
      设第 i 轮 , 传给发球者方案数为 f[i][0], 不传给发球者方案数为 f[i][1]
      显然, 有状态转方程:
      f[i][0] = f[i - 1][1]
      f[i][1] = (N - 1) * f[i - 1][0] + (N - 2) * f[i - 1][1]
    这玩意看起来可以用矩阵优化一下
    f[i - 1][0] f[i - 1][1]
    * (0) (N - 1)

    (1) (N - 2)
    =
    f[i][0] f[i][1]
    答案即 f[k][0] / ((N - 1) ^ k), 求乘法逆元即可
    总复杂度 O(4 ^ 3 log K )

  2. 出题人给出方法:

    我们把甲乙丙用123表示,这就是n=3的概率树。
    首先每一种传球的情况都对应树上的一条路径,而且在这里2和3是等价的,因为(1->2/3,2->3/1,3->2/1)
    于是就只有两种子树,以1为根或以其他为根
    以1为根的显然再回到1的概率是0,以其他为根的是1/2

    我们设初始点为第0层,那么到达第i层的任意一个节点概率都是1/(2^i))。
    我们用f[i]表示到达第i层即传球i次的结果。
    第一次传回的概率是f[1]=0,
    第二次是00+11/2,表示f[2]=上一层为1的情况0+上一层为”不是1”的情况1/2
    而我们可以发现,1->”不是1”,而”不是1”->1

    显然我们可以递推出每层为1的个数,再除以该层总数就是答案
    形式化的,设s[i]为第i层为1的个数,s[0]=1
    则s[i]=(2^(i-1))-s[i-1],f[i]=s[i]/(2^i),最后的f[k]就是答案。(其实并不需要f这个数组。)
    可以拿到七十分。

    但这还不够,第一题当然要把它A掉。
    考虑继续优化,
    看一下这个式子,
    s1=1-1,
    s2=2-1+1,
    s3=4-2+1-1,
    s4=8-4+2-1+1
    是不是发现了什么?
    每一次新的加入,都会把后面的每一项符号取反,
    而这个东西,显然可以用等比数列求和来做
    注意区分奇偶的影响。
    复杂度降到了log

    推广到n,k,的情况,只不过是把公比和项数换掉了,


T2:

题目中的单位价格 = 盒子价值 , 购买盒子之后 可以向其中任意放球

50 % 数据 :
将盒子容量类比体积, 盒子价值类比价值, 显然, 可以进行背包DP
设: f[i][j][k][l] 为: 考虑到第i个盒子, 红球已经放了j个, 蓝球已经放了k个, 使用了l个二元组的 最小价值
由于一个盒子 只能使用一次, 可以使用01背包 进行转移
总复杂度O(n ^ 4) 级别

100 % 数据 :

考虑对上述方法进行优化 :
填满了若干盒子后, 对最后剩下球的 种类数量 进行分类讨论:

  1. 最后剩下 1红1蓝 : 显然, 他们凑一凑, 比各占一个更优
  2. 最后剩下 1红0蓝 : 红球自占一个, 与和蓝球凑一凑 贡献相同
  3. 最后剩下 2红1蓝 : 红球自占一个 + 蓝球自占一个 与 一对凑一凑 + 自占一个 贡献相同
  4. 最后剩下 2红2蓝 : 同 3
  5. 最后剩下 3红2蓝 : 红球自占一个 + 蓝球自占一个 耗两盒子,
    2对凑一凑 + 自占一个 耗3盒子, 显然 自占更优
  6. 最后剩下 N红M蓝 : 同 2, 4, 5

由上, 只有最后红蓝球都剩下 1 时, 才有可能 "凑一凑" , 其他情况一盒内 只有一种球
则 可得知一性质 : 最多只会出现一次 "凑一凑" 的情况, 即最多使用一个二元组

则可将上述DP方程内 第四维[l] 变为 [0 / 1]
设 f[i,j,k,0]表示前i个盒子住j个A球,k个B球并且没有二元组的最小花

f[i,j,k,1]表示前i个盒子住j个A球,k个B球并且有一个二元组的最小花

在最优的情况下,一个盒子里面一定是满的小球,或者为空,或者是最后一小部分。
这样就可以转移了.注意特判它是最后一小部分的情况.
\(f[i,j,k,0]=min(f[i-1,j,k,0],f[i-1,j-v[i],k,0]+w[i],f[i-1,j,k-v[i],0]+w[i])\)
\(f[i,j,k,1]=min(f[i-1,j,k,1],f[i-1,j-v[i],k,1]+w[i],f[i-1,j,k-v[i],1]+w[i],f[i-1,j-1,k-1,0]+w[i])\)


T3:

40 % 数据 :
有 N 个节点的图最多只会染N种颜色, 且染N种颜色一定合法
可以搜索 暴力枚举每一个结点的染色情况, 将其染为[1, N]中的某种颜色
在染色时 检查是否与相邻的点撞色
取 最小的染色种类即可

100 % 数据 :
对于一棵树, 若按照题目给定方法转化为一张图,
显然, 各节点 会且只会向其祖先连边

有下列概念 :
弦 :连接环中不相邻的两个点的边。
弦图: 一个无向图称为弦图当图中任意长度大于3的环都至少有一个弦。
显然, 转化后的图 一定是一弦图.

则题目即为一 弦图最小染色数模板题, 利用最大势算法可解
复杂度O(n + m)


代码实现:

Day1 :

T1:

  • 考场代码 (正解):
#include <cstdio>
#include <cstring> 
#include <queue>
#include <ctype.h>
#define ll long long
const int MARX = 1e3 + 10;
//=============================================================
struct edge
{
    int v, w, ne;
}e[MARX << 1];
int num, N, head[MARX], dis[MARX];
bool vis[MARX];
ll ans;
//=============================================================
inline int read()
{
    int s = 1, w = 0; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') s = -1;
    for(; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0');
    return s * w;
}
void add(int u, int v, int w)
{
    e[++ num].v = v, e[num].w = w;
    e[num].ne = head[u]; head[u] = num;
}
void Bfs(int start)
{
    memset(vis, 0, sizeof(vis));
    ll sum0 = 0, sum1 = 0;
    std :: queue <int> q;
    q.push(start); dis[start] = 0, vis[start] = 1;
    
    while(! q.empty())
    {
      int u = q.front(); q.pop();
      for(int i = head[u]; i; i = e[i].ne)
        if(! vis[e[i].v])
        {
          dis[e[i].v] = (dis[u] + e[i].w) % 2;
          vis[e[i].v] = 1;
          q.push(e[i].v);
          
          sum0 += (! dis[e[i].v]), sum1 += dis[e[i].v];
          if(! dis[e[i].v]) ans += 3;
        }
    }
    
    ans += (sum0 - 1) * sum0;
//  ans += (ll)(sum0 - 2) * (ll)(sum0 - 1) * (ll)sum0 / 6 + (ll)(sum1 - 2) * (ll)(sum1 - 1) * (ll)sum1 / 6;
}
//=============================================================
int main()
{
    freopen("z.in", "r", stdin);
    freopen("z.out", "w", stdout);
    N = read(); ans += (ll) N;
    for(int i = 1; i < N; i ++)
    {
      int u = read(), v = read(), w = read() % 2;
      add(u, v , w), add(v, u , w);
    }
    
    for(int i = 1; i <= N; i ++) Bfs(i); 
    printf("%lld", ans);
    return 0;
}
/*
in
3
1 2 0
2 3 0
out
27

in
5
1 2 0
2 3 0
2 4 0
2 5 0
out
125
*/

T2:

  • 考场代码:
#include <cstdio>
#include <cstring>
#include <ctype.h>
#define ll long long
const int MARX1 = 10;
const ll mod = 1e9 + 7;
//=============================================================
int T, N , K, p[MARX1];
bool vis[MARX1];
ll ans;
//=============================================================
inline int read()
{
    int s = 1, w = 0; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') s = -1;
    for(; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0');
    return s * w;
}
ll qpow(ll x, ll y)
{
    ll ret = 1;
    while(y)
    {
      if(y & 1) ret = ret * x % mod;
      x = x * x % mod, y >>= 1;
    }
    return ret;
}
void check()
{
    for(int i = 1; i <= K; i ++)
    {
      memset(vis, 0, sizeof(vis));
      for(int j = p[i]; ; vis[j] = 1, j = p[j])
        if(j == 1) break;
        else if(vis[j]) return;
    }
    
//  for(int i = 1;i <= N; i ++) printf("%d ", p[i]);
//  printf("\n");
    
    ans = (ans + 1) % mod;
}
void dfs(int now)
{
    if(now > N) {check(); return ;}
    for(int i = 1; i <= N; i ++)
    {
      if(now <= K && i > K) continue;
      if(now > K && i <= K) continue;
      p[now] = i;
      dfs(now + 1);
    }
}
//=============================================================
int main()
{
    freopen("transfer.in", "r", stdin);
    freopen("transfer.out", "w", stdout);
    T = read();
    while(T --)
    {
      N = read(), K = read(); ans = 0;
      if(K == 1) ans = qpow((ll)N - 1, (ll)N - 1);
      else dfs(1);
      printf("%lld\n", ans);
    }
    return 0;
}
  • 正解 :
#include <cstdio>
const int mod = 1000000007;

int inline pls(int a, int b) { int m = a + b; return m < mod ? m : m - mod; }
int inline dec(int a, int b) { int m = a - b; return m < 0 ? m + mod : m; }
int inline mul(int a, int b) { return 1ll * a * b % mod; }
int pow(int a, int b) {
  int ans = 1;
  while (b) {
    if (b & 1) ans = mul(ans, a);
    a = mul(a, a), b >>= 1;
  }
  return ans;
}

int main() {
  freopen("transfer.in", "r", stdin);
  freopen("transfer.out", "w", stdout);
  int T, n, k;
  scanf("%d", &T);
  while (T--) {
    scanf("%d%d", &n, &k);
    printf("%d\n", mul(pow(n - k, n - k), pow(k, k - 1)));
  }
  return 0;
}

T3:

  • 考场代码:
#include <cstdio>
#include <cstring> 
#include <queue>
#include <ctype.h>
#define ll long long
const ll mod = 1e9 + 7;
const int MARX = 1e3 + 10;
//=============================================================
struct edge
{
    int v, w, ne;
}e[MARX << 1];
int num, N, M, head[MARX];
ll dis[MARX][MARX];
bool vis[MARX], diss[MARX][MARX]; 
//=============================================================
inline int read()
{
    int s = 1, w = 0; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') s = -1;
    for(; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0');
    return s * w;
}
void add(int u, int v, int w)
{
    e[++ num].v = v, e[num].w = w;
    e[num].ne = head[u]; head[u] = num;
}
ll qpow(ll x, ll y)
{
    ll ret = 1;
    while(y)
    {
      if(y & 1) ret = ret * x % mod;
      x = x * x % mod, y >>= 1;
    }
    return ret;
}
void Bfs(int start)
{
    memset(vis, 0, sizeof(vis));
    std :: queue <int> q;
    q.push(start); dis[start][start] = 0, vis[start] = 1;
    
    while(! q.empty())
    {
      int u = q.front(); q.pop();
      for(int i = head[u]; i; i = e[i].ne)
        if(! vis[e[i].v])
        {
          dis[start][e[i].v] = (dis[start][u] + (ll)e[i].w )% mod;
          diss[start][e[i].v] = (diss[start][u] + e[i].w % 2) % 2;
          vis[e[i].v] = 1;
          q.push(e[i].v);
        }
    }
}
//=============================================================
int main()
{
    freopen("meet.in", "r", stdin);
    freopen("meet.out", "w", stdout);
    N = read(), M = read();
    for(int i = 1; i < N; i ++)
    {
      int u = read(), v = read(), w = read();
      add(u, v , w), add(v, u , w);
    }
    for(int i = 1; i <= N; i ++) Bfs(i); 
    
    while(M --)
    {
      int x = read(), k = read(), node = 0;
      ll sum = 0;
      for(int i = 1; i <= N; i ++)
        if(diss[x][i] == k) node ++, sum = (sum + dis[x][i]) % mod;
      
      ll inv = qpow(node, mod - 2);
      sum = (sum * inv) % mod;
      printf("%lld\n", sum);
    }
    return 0;
}
  • 正解 :
#include <cstdio>
const int maxn = 100010;
const int mod = 1000000007;

int inline pls(int a, int b) { int m = a + b; return m < mod ? m : m - mod; }
int inline dec(int a, int b) { int m = a - b; return m < 0 ? m + mod : m; }
int inline mul(int a, int b) { return 1ll * a * b % mod; }
int pow(int a, int b) {
  int ans = 1;
  while (b) {
    if (b & 1) ans = mul(ans, a);
    a = mul(a, a), b >>= 1;
  }
  return ans;
}
int inline dvi(int a, int b) { return mul(a, pow(b, mod - 2)); }

struct edge {
  int v, w; edge *nxt;
  edge(int _v, int _w, edge *_nxt) : v(_v), w(_w), nxt(_nxt) {}
} *fi[maxn];

int ans[2][maxn];
long long so[maxn], se[maxn];
int no[maxn], ne[maxn];

void dfs(int u, int f = 0) {
  ne[u] = 1;
  for (edge *i = fi[u]; i; i = i->nxt) if (i->v != f) {
    dfs(i->v, u);
    if (i->w & 1) {
      so[u] = pls(so[u], pls(mul(i->w, ne[i->v]), se[i->v]));
      se[u] = pls(se[u], pls(mul(i->w, no[i->v]), so[i->v]));
      no[u] += ne[i->v], ne[u] += no[i->v];
    } else {
      so[u] = pls(so[u], pls(mul(i->w, no[i->v]), so[i->v]));
      se[u] = pls(se[u], pls(mul(i->w, ne[i->v]), se[i->v]));
      no[u] += no[i->v], ne[u] += ne[i->v];
    }
  }
}

void inline cr(int u, int v, int w) {
  if (w & 1) {
    so[u] = dec(so[u], pls(mul(w, ne[v]), se[v]));
    se[u] = dec(se[u], pls(mul(w, no[v]), so[v]));
    no[u] -= ne[v], ne[u] -= no[v];
    so[v] = pls(so[v], pls(mul(w, ne[u]), se[u]));
    se[v] = pls(se[v], pls(mul(w, no[u]), so[u]));
    no[v] += ne[u], ne[v] += no[u];
  } else {
    so[u] = dec(so[u], pls(mul(w, no[v]), so[v]));
    se[u] = dec(se[u], pls(mul(w, ne[v]), se[v]));
    no[u] -= no[v], ne[u] -= ne[v];
    so[v] = pls(so[v], pls(mul(w, no[u]), so[u]));
    se[v] = pls(se[v], pls(mul(w, ne[u]), se[u]));
    no[v] += no[u], ne[v] += ne[u];
  }
}

void gao(int u, int f = 0) {
  ans[0][u] = dvi(se[u], ne[u]);
  ans[1][u] = dvi(so[u], no[u]);
  for (edge *i = fi[u]; i; i = i->nxt) if (i->v != f) {
    cr(u, i->v, i->w); gao(i->v, u); cr(i->v, u, i->w);
  }
}

int main() {
  freopen("meet.in", "r", stdin);
  freopen("meet.out", "w", stdout);
  int n, m, u, v, w;
  scanf("%d%d", &n, &m);
  for (int i = 1; i < n; ++i) {
    scanf("%d%d%d", &u, &v, &w);
    fi[u] = new edge(v, w, fi[u]);
    fi[v] = new edge(u, w, fi[v]);
  }
  dfs(1); gao(1);
  while (m--) {
    scanf("%d%d", &u, &w);
    printf("%d\n", ans[w][u]);
  }
  return 0;
}

Day2 :

T1:

  • 考场代码 (正解):
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const ll mod = 1e9 + 7;
//=============================================================
int N, K, M = 2;
struct Matrix//结构体存数组 
{
    ll map[10][10];
} f, map, ans;
//=============================================================
Matrix operator * (const Matrix &a, const Matrix &b)//重载结构体运算符 
{
    Matrix c;
    memset(c.map, 0, sizeof(c.map));
    for(int k = 1; k <= M; k ++)//矩阵乘法, 对应相乘
      for(int i = 1; i <= M; i ++)
        for(int j = 1; j <= M; j ++)
          c.map[i][j] = (c.map[i][j] + a.map[i][k] * b.map[k][j] % mod + mod) % mod;
    return c;
}
inline int read()
{
    int s = 1, w = 0; char ch = getchar();
    for(; !isdigit(ch);ch=getchar()) if(ch == '-') s = -1;
    for(; isdigit(ch);ch=getchar()) w = (w << 1) + (w << 3) +ch-'0';
    return s*w;
}
void bulid(Matrix &map) {for(int i = 1; i <= M; i ++) map.map[i][i] = 1;}
void mul(Matrix &ans, int k)
{
    while(k)
    {
      if(k & 1) ans = ans * map;
      map = map * map, k >>= 1;
    }
}
ll qpow(ll x, ll y)
{
    ll ret = 1;
    while(y)
    {
      if(y & 1) ret = ret * x % mod;
      x = x * x % mod, y >>= 1;
    }
    return ret;
}
//=============================================================
int main()
{
    freopen("kasrra.in","r",stdin);
    freopen("kasrra.out","w",stdout);
    
    N = read(), K = read();
    if(K == 1) {printf("0"); return 0;}
    
    map.map[2][1] = 1;//构造原始矩阵 
    map.map[1][2] = (ll)N - 1ll, map.map[2][2] = (ll)N - 2ll;
    f.map[1][2] = N - 1ll, f.map[1][1] = 0;     
    
    bulid(ans), mul(ans, K - 1);//求快速幂 
    f = f * ans;
    ll inv = qpow(qpow((N - 1), K), mod - 2);
    printf("%lld\n",(f.map[1][1] * inv) % mod);
}

出题人做法:

#include<iostream>
#include<cstdio>
#include<ctype.h>
using namespace std;
const int mod=1e9+7;
inline int read(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch))f|=ch=='-',ch=getchar();
    while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
    return f?-x:x;
}
inline int Fast_pow(int b,int p){
    int ans=1;
    while(p){
        if(p&1)ans=1ll*ans*b%mod;
        b=1ll*b*b%mod;p>>=1;
    }
    return ans;
}
int main(){
    freopen("kasrra.in","r",stdin);
        freopen("kasrra.out","w",stdout);
    int n=read()-1,k=read(),ans,nn=1ll*n*n%mod;
    int a=1ll*(Fast_pow(nn,k/2)-1+mod)%mod*Fast_pow(nn-1,mod-2)%mod;
    int b=1ll*n*(Fast_pow(nn,(k-1)/2)-1+mod)%mod*Fast_pow(nn-1,mod-2)%mod;
    if(k&1)ans=(b-a+mod)%mod;
    else ans=(a-b+mod)%mod;
    printf("%d\n",1ll*ans*Fast_pow(Fast_pow(n,k-1),mod-2)%mod);
    return 0;
}


T2:

  • 考场代码:
#include <cstdio>
#include <ctype.h>
#define min(a, b) (a < b ? a : b)
#define ll long long
const int MARX = 310;
const int INF = 1e9;
//=============================================================
int A, B, M, K, ans = INF, w[MARX], v[MARX];
bool use[MARX];
//=============================================================
inline int read()
{
    int s = 1, w = 0; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') s = -1;
    for(; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0');
    return s * w;
}
void dfs(int now, int resA, int resB, int sum, int useK)
{
    if(sum >= ans) return;
    if(now > M) {if(resA <= 0 && resB <= 0) ans = min(ans, sum);  return ;}
    if(resA > 0) dfs(now + 1, resA - w[now], resB, sum + v[now], useK);
    if(resB > 0) dfs(now + 1, resA, resB - w[now], sum + v[now], useK);
    if(resA > 0 && resB > 0 && w[now] > 1 && useK > 0) dfs(now + 1, resA - 1, resB - 1, sum + v[now], useK - 1);
    dfs(now + 1, resA, resB, sum, useK);
}
//=============================================================
int main()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    
    A = read(), B = read(), M = read(), K = read();
    for(int i = 1;i  <= M; i ++) w[i] = read(), v[i] = read();
    if(M == 0)
    {
      if(A == 0 && B == 0) printf("0");
      else printf("Impossible");
    }
    dfs(1, A, B, 0, K);
    if(ans == INF) printf("Impossible");
    else printf("%d", ans);
    return 0;
}
/*
1 1 2 1
2 3
1 2
*/
  • 正解 :
#include <bits/stdc++.h>
using namespace std;
const int maxN = 305,INF = 1e9;
int a,b,m,k,w[maxN],v[maxN];
int f[maxN][maxN][maxN][2];

void dp(){
    for(int j = 0;j <= a;j ++) for(int k = 0;k <= b;k ++) f[0][j][k][0] = f[0][j][k][1] = INF;
    f[0][0][0][0] = 0;
    for(int i = 1;i <= m;i ++)
        for(int j = 0;j <= a;j ++)
            for(int k = 0;k <= b;k ++){
                f[i][j][k][0] = f[i - 1][j][k][0]; f[i][j][k][1] = f[i - 1][j][k][1];
                if(w[i] >= 2 && j >= 1&&k >= 1) f[i][j][k][1] = min(f[i][j][k][1],f[i - 1][j - 1][k - 1][0] + v[i]);
                    int sj = max(0,j - w[i]),sk = max(0,k - w[i]);
                    f[i][j][k][0] = min(f[i][j][k][0],f[i - 1][sj][k][0] + v[i]),
                            f[i][j][k][1] = min(f[i][j][k][1],f[i - 1][sj][k][1] + v[i]);
                    f[i][j][k][0] = min(f[i][j][k][0],f[i - 1][j][sk][0] + v[i]),
                            f[i][j][k][1] = min(f[i][j][k][1],f[i - 1][j][sk][1] + v[i]);
            }
}
int main() { 
        freopen("b.in","r",stdin);
        freopen("b.out","w",stdout);
    scanf("%d%d%d%d",&a,&b,&m,&k);
    for(int i=1;i<=m;i++) scanf("%d%d",&w[i],&v[i]);
    dp();
    int ans;
    if(k==0) ans=f[m][a][b][0];
    else ans=min(f[m][a][b][0],f[m][a][b][1]);
    if(ans!=INF) cout<<ans;
    else cout<<"Impossible"; 
}

T3:

  • 考场代码:
#include <cstdio>
#include <cstring>
#include <ctype.h>
#define max(a, b) (a > b ? a : b)
#define min(a, b) (a < b ? a : b)
#define ll long long
const int MARX = 2e3 + 10;
//=============================================================
struct edge
{
    int v, ne;
}e[200 * MARX];
int num, T, N, tot, ans, head[MARX], color[MARX];
bool use[MARX], vis[MARX];
//=============================================================
inline int read()
{
    int s = 1, w = 0; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') s = -1;
    for(; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0');
    return s * w;
}
void add(int u, int v) {e[++ num].v = v, e[num].ne = head[u], head[u] = num;}
void dfs(int u)
{
    if(ans <= tot) return;
    if(u > N) {ans = min(ans, tot); return ;}
    for(int i = 1; i <= N; i ++)
    {
      bool flag = 0;
      for(int j = head[u]; j; j = e[j].ne)
        if(color[e[j].v] == i) {flag = 1;break;}
      if(flag) continue;
      
      bool usei = use[i];
      color[u] = i, use[i] = 1, tot += (! usei);
      dfs(u + 1);
      use[i] = usei, tot -= (! usei);
    }
}
void dfs1(int u, int dep)
{
    vis[u] = 1, ans = max(ans, dep);
    for(int i = head[u]; i; i = e[i].ne)
      if(! vis[e[i].v]) dfs1(e[i].v, dep + 1);
}
//=============================================================
int main()
{
    freopen("wa.in","r",stdin);
    freopen("wa.out","w",stdout);
    
    T = read();
    while(T --)
    {
      ans = MARX, num = 0;
      memset(head, 0, sizeof(head));
      memset(use, 0, sizeof(use));
      memset(color, 0, sizeof(color));
      
      N = read();
      if(N > 2000) {printf("Koishi_No.1!"); return 0;}
      
      while(1)
      {
        int u = read(), v = read();
        if(u == - 1 && v == - 1) break;
        add(u, v), add(v, u);
      }
      
      if(T == 1 && N > 10) ans = 0, dfs1(1, 1); 
      else dfs(1);
      printf("%d\n", ans);
    }
    return 0;
}
  • 正解 :
#include <cmath>
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 10;
const int maxm = 4000000 + 10;
int n, t, head[maxn], vis[maxn], val[maxn], col[maxn], bgn[maxn], edge_num, ans;

vector<int> v[maxn];

struct Edge { int v, nxt; } edge[maxm << 1];

inline void Add_edge(int u, int v) {
  edge[++edge_num].v = v, edge[edge_num].nxt = head[u], head[u] = edge_num;
}

int main(int argc, char const *argv[])
{
  freopen("wa.in", "r", stdin), freopen("wa.out", "w", stdout);

  scanf("%d", &n);
  while( ~scanf("%d", &n) ) {
    t = 0, ans = 0;
    memset(val, 0, sizeof val), memset(vis, 0, sizeof vis), memset(col, 0, sizeof col), memset(bgn, 0, sizeof bgn);
    memset(head, 0, sizeof head), edge_num = 0;
    for(int u = 1, x = 1, i = 1; ; ++i) {
      scanf("%d%d", &u, &x);
      if( u == - 1 && x == - 1 ) break; else Add_edge(u, x), Add_edge(x, u);
    }
    for(int i = 1; i <= n; ++i) v[0].push_back(i);
    for(int x = 0, i = 1; i <= n; ++i) {
      for(int f = 0; ; ) {
        for(int j = v[t].size() - 1; j >= 0; --j) {
          if( vis[v[t][j]] ) v[t].pop_back();
          else {
            f = 1, x = v[t][j];
            break;
          }
        }
        if( f == 0 ) t = t - 1; else break;
      }
      vis[x] = 1;
      for(int j = head[x]; j; j = edge[j].nxt) {
        if( vis[edge[j].v] == 0 ) v[++val[edge[j].v]].push_back(edge[j].v), t = max(t, val[edge[j].v]);
        bgn[col[edge[j].v]] = x;
      }
      for(int j = 1; j; ++j) if( bgn[j] != x ) {
        col[x] = j;
        break;
      }
    }
    for(int i = 1; i <= n; ++i) ans = max(ans, val[i] + 1);
    printf("%d\n", ans);
  }

  return 0;
}

猜你喜欢

转载自www.cnblogs.com/luckyblock/p/11830996.html