Loading

2021, 8,24 模拟赛

期望:score: 100 + 20 + 40 = 160

实际:score: 0 + 0 + 20 = 20

总结

这波直接亏大了 QWQ

T1 没取模 CE 直接挂 100 -> 0

T2 写了 20 分 std 数据是假的。

T3 写了 40 分部分分的爆搜,洛谷 \(O^2\) 能到 40,众所周知机房评测鸡。。。

虽然比赛挂了,但学到了好多.....

T1 monitor

题面

solution

字符串匹配

KMP ? AC 自动机 ?

啥呀,\(hash\) 完全可以水过 = =

\(map\) 映射 \(n\) 个字符串的 \(hash\) 值,因为它们长度是一个样的,所以可以 \(O(L)\) 扫一遍长串判断即可。

code

/*
work by:Ariel_
Knowledge:
Time:
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <map>
#define int long long
#define ll long long
#define rg register
using namespace std;
const int seed = 27;
const ll mod = 1e9 + 7;
const ll Mod = 1e9 + 9;
const int MAXN = 1e5 + 5;
int read(){
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
    return x*f;
}
int L, n, m, tot; 
char s[30], a[MAXN];
map<int, bool>happen, Happen; 
signed main(){
   //freopen("monitor.in", "r", stdin);
   //freopen("monitor,out", "w", stdout);
   L = read(), n = read(), m = read();
   for (int i = 1; i <= n; i++) {
   	  scanf("%s", s + 1);
   	  ll base = 1;
   	  for(int j = 1; j <= m; j++) base = (base * seed % mod + (s[j] - 'a' + 1)) % mod;  
	  if (!happen[base]) happen[base] = 1;
	  base = 1;
	  for(int j = 1; j <= m; j++) base = (base * seed % Mod + (s[j] - 'a' + 1)) % Mod;  
	  if (!Happen[base]) Happen[base] = 1;
   }
   scanf("%s", a + 1); 
   for (int i = 1; i <= L; i++) {
   	  if (i + m - 1 > L) {printf("no"); return 0;}
   	  ll H = 1, h = 1;
	  for (int j = i; j <= i + m - 1; j++) h = (h * seed % mod + (a[j] - 'a' + 1)) % mod;
	  for (int j = i; j <= i + m - 1; j++) H = (H * seed % Mod + (a[j] - 'a' + 1)) % Mod;
	  if(happen[h] && Happen[H]) {printf("%lld", i);return 0;}
   }
   puts("");
   return 0;
}

T2 lab

题面

solution

结论:两点间的路径可以等于树上原来两点的路径加上任意倍的树上所有环长度的 \(gcd\)

证明:

路径权值具有相反性,只要有环,要么不走,要么等效的走完。

假设现在有 \(k\) 个环,每个环的边权和为 \(x_i\) ,求 \(x,y\) 两点的路径是否可能为 \(t\)\(x,y\) 两点的树上路径为 \(dis_{i, j}\)

有不定方程 \(dis_{i, j} + \sum_{i = 1}^{i \leq k} c_i x_i = t\) \(c\) 为任意非负整数

根据裴蜀定理:

化简得到 \(dis_{i, j} + K\times gcd^{i\leq k}_{i = 1}(x_i\dots) = t\)

然后得到 \(dis_{i, j} \equiv t (mod ~gcd^{i\leq k}_{i = 1}(x_i\dots))\)

code

/*
work by:Ariel_
Knowledge:
Time:
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define ll long long
#define rg register
using namespace std;
const int MAXN = 1e5 + 5;
ll read(){
    ll x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
    return x*f;
}
ll n, T, tot, dis[MAXN], g;
struct edge{ll w, v, nxt;}e[MAXN << 1];
ll head[MAXN], E;
void add_edge(ll u, ll v, ll w) {
  e[++E] = (edge) {w, v, head[u]};
  head[u] = E;
}
namespace LCA{
  int dep[MAXN], top[MAXN], fa[MAXN], tot, siz[MAXN], son[MAXN], dfn[MAXN];
  void dfs(int x, int f) {
  	dep[x] = dep[f] + 1, fa[x] = f, siz[x] = 1;
  	for (int i = head[x]; i; i = e[i].nxt) {
  		   ll v = e[i].v;
  		   if(v == f) continue;
  		   dis[v] = dis[x] + e[i].w;
		   dfs(v, x);
  		   siz[x] += siz[v];
  		   if(siz[son[x]] < siz[v]) son[x] = v;
	  }
  }
  void dfs2(int x, int tp) {
  	 top[x] = tp;
  	 if (son[x]) dfs2(son[x], tp);
  	 for (int i = head[x]; i; i = e[i].nxt) {
  	 	   int v = e[i].v;
  	       if(v == fa[x] || v == son[x]) continue;
		   dfs2(v, v);	   
	  }
  }
  int lca(int x, int y) {
  	 while(top[x] != top[y]) {
  	   if(dep[top[x]] < dep[top[y]]) swap(x, y);
	   x = fa[top[x]]; 	 
	}
	if (dep[x] > dep[y]) swap(x, y);
	return x;
  }
}
using namespace LCA;
ll gcd(ll a, ll b) {return b == 0 ? a:gcd(b, a % b);}
signed main(){
   //freopen("lab.in", "r", stdin);
   //freopen("lab.out", "w", stdout);
   n = read(), T = read();
   for (int i = 1, u, v, w; i < n; i++){
   	  u = read(), v = read(), w = read();
   	  add_edge(u, v, w), add_edge(v, u, -w);
   }
   dfs(1, 0), dfs2(1, 1); 
   for (int i = 1; i <= T; i++) {
     ll opt = read(), x = read(), y = read(); int t = read();
     ll _lca = lca(x, y);
     ll Dis = -(dis[x] - dis[_lca]) + (dis[y] - dis[_lca]);
	 if (opt) {
	 	Dis = t - Dis; Dis = abs(Dis);
        if(!g) {
          if(Dis) printf("no\n");
          else printf("yes\n");
		}
		else {
		   Dis = (Dis % g + g) % g;
		   if(Dis) printf("no\n");
		   else printf("yes\n");
		}
	 }
	 else g = gcd(g, abs(Dis - t));
   }
   puts("");
   return 0;
}

T3 civilization

题面

solution

树形 \(dp\) ,反正我没想到 /kk

\(f_{u, 1|0}\) 表示以 \(u\) 为根的子树内到 \(u\) 点路径长度为奇数|偶数所有路径的长度和。

\(siz_{u, 1|0}\) 表示以 \(u\) 为根的子树内到 \(u\) 点路径长度为奇数|偶数所有点的个数。

计算出一个点的答案然后换根,求其他的点。

转移很麻烦。

code

/*
work by:Ariel_
Knowledge:
Time:
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#define ll long long
#define rg register
using namespace std;
const int MAXN = 2e5 + 5;
int read(){
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') {x = x*10 + c - '0'; c = getchar();}
    return x*f;
}
int n, q, siz[2][MAXN], siz2[2][MAXN];
ll f[2][MAXN], ans[2][MAXN];
struct edge{int v, nxt, w;}e[MAXN];
int E, head[MAXN];
void add_edge(int u, int v, int w) {
   e[++E] = (edge){v, head[u], w};
   head[u] = E;
}
void dfs(int x, int fa) {
   siz[0][x] = 1;
   for (int i = head[x]; i; i = e[i].nxt) {
   	  int v = e[i].v, w = e[i].w;
   	  if (v == fa) continue;
   	  dfs(v, x);
   	  if(w & 1) {
   	     siz[0][x] += siz[1][v], siz[1][x] += siz[0][v];
	     f[1][x] += f[0][v] + siz[0][v] * w;
	     f[0][x] += f[1][v] + siz[1][v] * w;
	  }
	  else {
	  	 siz[0][x] += siz[0][v], siz[1][x] += siz[1][v];
	  	 f[1][x] += f[1][v] + siz[1][v] * w;
	  	 f[0][x] += f[0][v] + siz[0][v] * w;
	  }
   }
}
void dfs2(int x, int fa) {
   for (int i = head[x]; i; i = e[i].nxt) {
   	    int v = e[i].v, w = e[i].w;
   	    if (v == fa) continue;
   	    if (w & 1) {
   	       siz2[0][v] = siz2[1][x], siz2[1][v] = siz2[0][x];
		   ans[0][v] = f[0][v] + ans[1][x] - (f[0][v] + w * siz[0][v]) + w * (siz2[1][x] - siz[0][v]);
		   ans[1][v] = f[1][v] + ans[0][x] - (f[1][v] + w * siz[1][v]) + w * (siz2[0][x] - siz[1][v]);	
		}
       else {
       	   siz2[0][v] = siz2[0][x], siz2[1][v] = siz2[1][x];
       	   ans[0][v] = f[0][v] + ans[0][x] -(f[0][v] + w * siz[0][v]) + w * (siz2[0][x] - siz[0][v]);
	       ans[1][v] = f[1][v] + ans[1][x] - (f[1][v] + w * siz[1][v]) + w * (siz2[1][x] - siz[1][v]);
	   }
	   dfs2(v, x);
   }
}
int main(){
   n = read(), q = read();
   for (int i = 1, u, v, w; i < n; i++) {
   	   u = read(), v = read(), w = read();
   	   add_edge(u, v, w), add_edge(v, u, w);
   }
   dfs(1, 0);  
   ans[0][1] = f[0][1], ans[1][1] = f[1][1];
   siz2[0][1] = siz[0][1], siz2[1][1] = siz[1][1];
   dfs2(1, 0);
   for (int i = 1; i <= q; i++) {
   	  int x = read();
   	  printf("%lld %lld\n", ans[1][x], ans[0][x]);
   }
   puts("");
   return 0;
}

posted @ 2021-08-24 21:21  Dita  阅读(42)  评论(2编辑  收藏  举报