2020.8.27 解题报告

2020.8.27


答题情况

总成绩 : 50 , 排名 : 4 / 6
T1 : 20 T2 : 0 T3 : 30

各题目分析

题目 1 :
预估成绩 : 100 实际成绩 : 20 考试用时 : 7:30 ~ 8:10

先想到爆搜,觉得过不去写了贪心。
贪心被卡了。

题目 2 :
预估成绩 : 0 实际成绩 : 0 考试用时 : 10:00 ~ 10:40

思维题,想不到。

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

写了 \(O(n^2\log n)\) 的暴力。


题目解析

T1

\(n\le 10^9\),最多只有 9 位,\(t<9\),任意次交换后至多有 \(9!=362880\) 种结果。
考虑爆搜枚举交换的位置,交换次数不多于 \(\min(k, t!)\)

搜出最大/最小值即可。


T2

考虑两次连续的操作 \([l,l+k-1]\)\([l+1,l+k]\),仅有 \(l\)\(l+k\) 状态被改变。
同理,考虑四次连续的操作 \([l,l+k-1], [l+1,l+k], [l+k,l+2k-1]\)\([l+k+1, l+2k]\),仅有 \(l\)\(l+2k\) 状态被改变。
发现可令任意两个距离为 \(k\) 的倍数的位置同时取反。

考虑每 \(k\) 个位置分为一组,每一组相同位置的数 距离为 \(k\) 的倍数。
考虑对相同位置的数进行操作。
若这些数中有偶数个 \(0\),则可以通过每次减少两个 \(0\),使它们全部变为 \(1\),从而对答案有贡献。
如果有奇数个 \(1\),进行若干次操作后,必然会剩下一个 \(0\) 位置。可通过多次操作使 \(0\) 位置出现在任何一个数的地方,应使 \(0\) 位置位于权值较小的数上。

仅仅这样做似乎有些漏洞,比如这组数据:\(\text{1001}\)
如果仅按照上面的做法,那么钦定了 \(1{\underline {0}}0{\underline {1}}\) 这两个位置 \(01\) 情况必须不同。
考虑先进行一次操作,变为:\(\text{0101}\),改变了相同位置的数的奇偶性,不会漏解。


T3

考虑一条边 \((x,y, w)\) 的影响。
发现他只影响其祖先节点的答案。
\(x\) 为树上父节点,则 \((x,y, w)\)\(ans_x\) 的影响为 \(w\times size_y\times (size_x - size_y)\)
祖先节点同理,设 \(z\) 为祖先,则 \((x,y, w)\)\(ans_z\) 的贡献为 \(w\times size_y \times (size_z - size_y)\)

贡献仅与 \(size_y\) 有关,考虑将边权转为点权,赋值给 \(y\)
考虑树上一个节点 \(x\) 的答案,化下式子:

\[\begin{aligned} ans_x &= \sum_{y\in son_x}{w_y \times size_y\times (size_x - size_y)}\\ ans_x &= size_x\times \sum_{y\in son_x}{w_y \times size_y} - \sum_{y\in son_x}{w_y \times {size_y}^2} \end{aligned}\]

\(\sum\) 项仅与 \(y\) 有关,考虑线段树维护这两个值的区间和,上树剖即可。
复杂度 \(O(m\log^2 n)\)


代码实现

T1 :

考场代码

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const int kMaxn = 10 + 10;
//=============================================================
int t, num[kMaxn], sorted[kMaxn], rk[kMaxn];
int tmpnum[kMaxn], tmprk[kMaxn];
//=============================================================
inline ll read() {
	ll f = 1, w = 0; char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
	return f * w;
}
ll GetMax(ll k_) {
  for (int i = 1; i <= t; ++ i) {
    tmpnum[i] = num[i];
    tmprk[i] = rk[i]; 
  }
  for (int i = 1; i <= t && k_; ++ i) {
    int rki = tmprk[i], rkj = 0, pos;
    for (int j = i + 1; j <= t; ++ j) {
      if (tmprk[j] > rkj) {
        rkj = tmprk[j];
        pos = j;
      }
    }
    if (rkj > rki) {
      std :: swap(tmpnum[i], tmpnum[pos]);
      std :: swap(tmprk[i], tmprk[pos]); 
      -- k_;
    }
  }
  ll ret = 0, pow = 1;
  for (int i = t; i >= 1; -- i) {
    ret += tmpnum[i] * pow;
    pow *= 10;
  }
  return ret;
}
ll GetMin(ll k_) {
  for (int i = 1; i <= t; ++ i) {
    tmpnum[i] = num[i];
    tmprk[i] = rk[i]; 
  }
  for (int i = 1; i <= t && k_; ++ i) {
    int rki = tmprk[i], rkj = 10, pos;
    for (int j = i + 1; j <= t; ++ j) {
      if (i == 1) {
        if (tmprk[j] < rkj && tmpnum[j]) {
          rkj = rk[j];
          pos = j;
        }
        continue ;
      }
      if (tmprk[j] < rkj) {
        rkj = tmprk[j];
        pos = j;
      }
    }
    if (rkj < rki) {
      std :: swap(tmpnum[i], tmpnum[pos]);
      std :: swap(tmprk[i], tmprk[pos]); 
      -- k_;
    }
  }
  ll ret = 0, pow = 1;
  for (int i = t; i >= 1; -- i) {
    ret += tmpnum[i] * pow;
    pow *= 10;
  }
  return ret;
}
//=============================================================
int main() {
  freopen("cooperate.in", "r", stdin);
  freopen("cooperate.out", "w", stdout);
  ll T = read();
  while (T --) {
    ll n = read(), k = read(), tmp = n;
    for (t = 0; tmp; tmp /= 10) {
      ++ t;
      num[t] = sorted[t] = tmp % 10;
    }
    std :: sort(sorted + 1, sorted + t + 1);
    for (int i = 1, j = t; i <= j; ++ i, -- j) std :: swap (num[i], num[j]);
    for (int i = 1; i <= t; ++ i) {
      for (int j = 1, rkj = 0; j <= t; ++ j) {
        if (sorted[j] != sorted[j - 1]) rkj ++;
        if (sorted[j] == num[i]) {
          rk[i] = rkj;
          break;
        }
      }
    }
    printf("%lld\n", GetMax(k) - GetMin(k));
  }
	return 0;
}

正解

#include<bits/stdc++.h>
using namespace std;
 
int maxx, minn, k, len;
int c[20], sum1[20], sum2[20], p[20];
char ss[20];
 
void update() {
    if (c[p[1]] == 0) return;
    for (int i = 1; i <= len; i++)
        sum1[i] = p[i];
    int kk = 0, s = 0;
    for (int i = 1; i <= len; i++) {
        s = s * 10 + c[p[i]];
        if (sum1[i] != i) {
            for (int j = i+1; j <= len; j++) {
                if (sum1[j] == i) {
                    swap(sum1[i], sum1[j]);
                    kk++;
                    if(kk > k) return;
                    break;
                }
            }
        }
    }
    if(kk > k) return;
    maxx = max(maxx, s);
    minn = min(minn, s);
}
 
int main() {
    freopen("cooperate.in", "r", stdin);
    freopen("cooperate.out", "w", stdout);
    int t;
    scanf("%d", &t);
    while(t--) {
        memset(sum1,0,sizeof(sum1));
        memset(sum2,0,sizeof(sum2));
        scanf("%s%d",ss,&k);
        len = strlen(ss);
        for(int i = 0; i < len; i++) {
            c[i+1] = ss[i] - '0';
            sum1[c[i+1]]++;
            sum2[c[i+1]]++;
        }
        if(k >= len-1) {
            minn = maxx = 0; 
            for(int i = 1; i <= 9; i++) {
                if(sum1[i]) {
                    minn = minn*10 + i; 
                    sum1[i]--;
                    break;
                }
            }
            for(int i = 0; i <= 9; i++) {
                while(sum1[i]) {
                    minn = minn*10 + i;
                    sum1[i]--;
                }
            }
            for(int i = 9; i >= 0; i--) {
                while(sum2[i]) {
                    maxx = maxx*10 + i;
                    sum2[i]--;
                }
            }
            printf("%d\n", maxx - minn);
            continue;
        }

        for(int i = 1; i <= len; i++)
            p[i] = i;
        minn = 2e9, maxx = -1;
        do
            update();
        while(next_permutation(p+1, p+len+1));
        printf("%d\n", maxx - minn);
    }
    return 0;
}

T2:

正解

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstdlib>
using namespace std;

#define maxN 2050
#define oo 10000000

int T;
int N, K;
int state[maxN], a[maxN];

int Solve(int N, int K, int state[], int a[])
{
	int res = 0;
	for (int i = 1; i <= K; ++ i) 
	{
		int cnt = 0, minv = oo;
		for (int j = i; j <= N; j += K)
		{
			res += a[j];
			minv = min(minv, a[j]);
			if (state[j] == 0) ++ cnt; 
		}
		
		if (cnt & 1) res -= minv;
	}
	return res;
}

int main()
{
	freopen("challenge.in", "r", stdin);
	freopen("challenge.out", "w", stdout);
	
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d", &N, &K);
		for (int i = 1; i <= N; ++ i) scanf("%d", state+i);
		for (int i = 1; i <= N; ++ i) scanf("%d", a+i);
		int Ans = 0;
		if (K == 1) 
		{
			for (int i = 1; i <= N; ++ i) Ans += a[i];
		}
		else
		{
			Ans = Solve(N, K, state, a);
			for (int i = 1; i <= K; ++ i) state[i] ^= 1;
			Ans = max(Ans, Solve(N, K, state, a));
		}
		printf("%d\n", Ans);
	}
	
	return 0;
}

T3:

考场代码

//
/*
By:Luckyblock
*/
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const int kMaxn = 5e4 + 10;
const int kMod = 2019;
//=============================================================
int n, q, root, edge_num, head[kMaxn], u[kMaxn << 1], v[kMaxn << 1], w[kMaxn << 1], ne[kMaxn << 1];
int size[kMaxn], dep[kMaxn], fa[kMaxn], son[kMaxn], top[kMaxn];
int Dfn, dfn[kMaxn];
//=============================================================
inline ll read() {
	ll f = 1, w = 0; char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
	return f * w;
}
struct SegmentTree {
  #define ls (now_<<1)
  #define rs (now_<<1|1)
  #define mid ((L_+R_)>>1)
  int prod[kMaxn << 2], minus[kMaxn << 2];
  void Modify(int now_, int L_, int R_, int ql_, int qr_, int p_, int m_) {
    if (ql_ <= L_ && R_ <= qr_) {
      prod[now_] += p_; prod[now_] %= kMod;
      minus[now_] += m_; minus[now_] %= kMod;
      return ;
    }
    if (ql_ <= mid) Modify(ls, L_, mid, ql_, qr_, p_, m_);
    if (qr_ > mid) Modify(rs, mid + 1, R_, ql_, qr_, p_, m_);
  }
  int Query(int now_, int L_, int R_, int pos_, int size, int p_) {
    p_ += prod[now_];
    int m = minus[now_], ret;
    if (L_ == R_) return (p_ * size % kMod - m)% kMod;
    if (pos_ <= mid) ret = Query(ls, L_, mid, pos_, size, p_);
    else ret = Query(rs, mid + 1, R_, pos_, size, p_);
    return (ret - m + kMod) % kMod;
  }
} t;
void AddEdge(int u_, int v_, int w_) {
  u[++ edge_num] = u_, v[edge_num] = v_, w[edge_num] = w_;
  ne[edge_num] = head[u_], head[u_] = edge_num;
}
void Dfs1(int u_, int fa_) {
  size[u_] = 1;
  fa[u_] = fa_;
  dep[u_] = dep[fa_] + 1;
  for (int i = head[u_]; i; i = ne[i]) {
    int v_ = v[i];
    if (v_ == fa_) continue ;
    Dfs1(v_, u_);
    size[u_] += size[v_];
    if (size[son[u_]] < size[v_]) son[u_] = v_;
  }
}
void Dfs2(int u_, int top_) {
  dfn[u_] = ++ Dfn;
  top[u_] = top_;
  if (son[u_]) Dfs2(son[u_], top_);
  for (int i = head[u_]; i; i = ne[i]) {
    int v_ = v[i];
    if (v_ == fa[u_] || v_ == son[u_]) continue ;
    Dfs2(v_, v_);
  }
}
void ModifyChain(int u_, int v_, int prod_, int minus_) {
  for (; top[u_] != top[v_]; u_ = fa[top[u_]]) {
    if (dep[top[u_]] < dep[top[v_]]) {
      std :: swap(u_, v_); 
    }
    t.Modify(1, 1, n, dfn[top[u_]], dfn[u_], prod_, minus_);
  }
  if (dep[u_] > dep[v_]) std :: swap(u_, v_);
  t.Modify(1, 1, n, dfn[u_], dfn[v_], prod_, minus_);
}
void Modify(int u_, int v_, int w_) {
  int tmpu = u_, tmpv = v_;
  for (; top[tmpu] != top[tmpv]; tmpu = fa[top[tmpu]]) {
    if (dep[top[tmpu]] < dep[top[tmpv]]) {
      std :: swap(tmpu, tmpv); 
    }
  }
  int lca = (dep[tmpu] > dep[tmpv] ? tmpv : tmpu);
  for (; u_ != lca; u_ = fa[u_]) {
    ModifyChain(fa[u_], 1, w_ * size[u_] % kMod, 
                w_ * size[u_] * size[u_] % kMod); 
  }
  for (; v_ != lca; v_ = fa[v_]) {
    ModifyChain(fa[v_], 1, w_ * size[v_] % kMod, 
                w_ * size[v_] * size[v_] % kMod); 
  }
}
//=============================================================
int main() {
  freopen("network.in", "r", stdin);
  freopen("network.out", "w", stdout);
  n = read(), q = read();
  root = 1;
  for (int i = 2; i <= n; ++ i) {
    int x = read(), y = i, z = read();
    AddEdge(x, y, z);
  }
  Dfs1(root, 0), Dfs2(root, root);
  for (int i = 1; i <= edge_num; i ++) {
    int x = u[i], y = v[i], z = w[i];
    Modify(x, y, z);
  }
  while (q --) {
    char opt[10]; scanf("%s", opt + 1);
    if (opt[1] == 'I') {
      int x = read(), y = read(), z = read();
      Modify(x, y, z);
    } else {
      int x = read();
      printf("%d\n", t.Query(1, 1, n, dfn[x], size[x], 0));
    }
    
  }
	return 0;
}
/*
5 5
1 1
2 5
1 2
2 1
ASK 1
ASK 2
ASK 3
ASK 4
ASK 5
*/ 
/*
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const int kMaxn = 5e4 + 10;
//=============================================================
int root, edge_num, head[kMaxn], v[kMaxn << 1], w[kMaxn << 1], ne[kMaxn << 1];
//=============================================================
inline ll read() {
	ll f = 1, w = 0; char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
	return f * w;
}
void AddEdge(int u_, int v_, int w_) {
  v[++ edge_num] = v_, w[edge_num] = w_;
  ne[edge_num] = head[u_], head[u_] = edge_num;
}
void Dfs(int u_, int fa_) {
  for (int i = head[u_]; i; i = ne[i]) {
    int v_ = v[i];
    if (v_ == fa_) continue ;
    
  }
}
//=============================================================
int main() {
  int n = read(), q = read();
  for (int i = 1; i < n; ++ i) {
    int u = read(), v = i, w = read();
    if (u == v) root = i;
    AddEdge(u, v, w), AddEdge(v, u, w);
  }
  Dfs(root, 0);
	return 0;
}

*/

正解

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <utility>
#include <vector>
using namespace std;

#define maxN 100050
#define Mod 2019

int N;
int fa[maxN], v[maxN];
vector<int> H[maxN];
int siz[maxN], top[maxN], son[maxN], dep[maxN];
int sum_siz[maxN], sum_siz2[maxN];
pair<int,int> govern[maxN];

namespace Segment_tree
{
	struct Tnode
	{
		int s1, s2, add;
	} tree[maxN * 4];
	void Modify(int r, int x, int y, int p)
	{
		tree[r].s1 = (tree[r].s1 + p * (sum_siz[y] - sum_siz[x-1])) % Mod;
		tree[r].s2 = (tree[r].s2 + p * (sum_siz2[y] - sum_siz2[x-1])) % Mod;
		tree[r].add = (tree[r].add + p ) % Mod; 
	}
	void Down(int r, int L, int R, int mid)
	{
		Modify((r<<1), L, mid, tree[r].add);
		Modify(((r<<1)^1), mid+1, R, tree[r].add);
		tree[r].add = 0;
	}
	void update(int r, int L, int R, int x, int y, int p)
	{
		if (x > R || y < L) return ;
		if (L >= x && R <= y) 
		{
			Modify(r, L, R, p);
			return ;
		}
		int mid = (L+R) >> 1;
		Down(r, L, R, mid);
		update((r<<1), L, mid, x, y, p);
		update(((r<<1)^1), mid+1, R, x, y, p);
		tree[r].s1 = (tree[r<<1].s1 + tree[(r<<1)^1].s1) % Mod;
		tree[r].s2 = (tree[r<<1].s2 + tree[(r<<1)^1].s2) % Mod;
	}
	pair<int,int> ask(int r, int L, int R, int x, int y)
	{
		if (x > R || y < L) return make_pair(0, 0);
		if (L >= x && R <= y) return make_pair(tree[r].s1, tree[r].s2);
		int mid = (L+R)>>1;
		Down(r, L, R, mid);
		pair<int,int> res1 = ask((r<<1), L, mid, x, y),
					  res2 = ask(((r<<1)^1), mid+1, R, x, y);
		return make_pair((res1.first + res2.first) % Mod, 
						 (res1.second + res2.second) % Mod);
	}
	void Update(int x, int y, int p)
	{
		update(1, 1, N, x, y, p);	
	}
	pair<int,int> Ask(int x, int y)
	{
		return x <= y ? ask(1, 1, N, x, y) : make_pair(0, 0);
	}
}

void Dfs(int r, int top_id, int &T)
{
	top[r] = top_id;
	govern[r].first = ++ T;
	sum_siz[T] = (sum_siz[T - 1] + siz[r]) % Mod;
	sum_siz2[T] = (sum_siz2[T - 1] + (siz[r]%Mod) * (siz[r]%Mod)) % Mod;;
	if (son[r]) Dfs(son[r], top_id, T);
	for (int i = 0; i < (int)H[r].size(); ++ i) 
		if (H[r][i] != son[r]) 
			Dfs(H[r][i], H[r][i], T);
	govern[r].second = T;
}

void Init()
{
	static int q[maxN];
	int head = 1, tail = 1;
	q[1] = 1;
	dep[1] = 1;
	while (head <= tail) 
	{
		int cur = q[head ++];
		for (int i = 0; i < (int)H[cur].size(); ++ i) 
		{
			dep[ H[cur][i] ] = dep[cur] + 1;
			q[++tail] = H[cur][i];	
		}
	}
	for (int i = N; i >= 1; -- i) 
	{
		int cur = q[i];
		siz[cur] = 1;
		son[cur] = 0;
		for (int j = 0; j < (int)H[cur].size(); ++ j) 
		{
			int nxt = H[cur][j];
			siz[cur] += siz[nxt];
			if (son[cur] == 0 || siz[nxt] > siz[son[cur]]) 
				son[cur] = nxt;
		}
	}
	int T = 0;
	Dfs(1, 1, T);
}

void Update_path(int u, int v, int w)
{
	if (top[u] == top[v])
	{
		if (u == v) return ;
		if (dep[u] > dep[v]) swap(u, v);
		Segment_tree::Update(govern[u].first+1, govern[v].first, w);
		return ;
	}
	if (dep[ top[u] ] < dep[ top[v] ]) swap(u, v);
	Segment_tree::Update(govern[top[u]].first, govern[u].first, w);
	Update_path(fa[top[u]], v, w);
}

int main()
{
	freopen("network.in", "r", stdin);
	freopen("network.out", "w", stdout);
	
	int Q;
	scanf("%d%d", &N, &Q);
	for (int i = 2; i <= N; ++ i) 
	{
		scanf("%d%d", fa+i, v+i);
		H[ fa[i] ].push_back(i);
	}
	
	Init();
	
	for (int i = 2; i <= N; ++ i) 
		Segment_tree::Update(govern[i].first, govern[i].first, v[i]);
		
	while (Q--)
	{
		char order[5];
		scanf("%s", order);
		if (order[0] == 'A')
		{
			int x;
			scanf("%d", &x);
			pair<int,int> tmp = Segment_tree::Ask(govern[x].first+1, govern[x].second);
			int res = (siz[x] * tmp.first - tmp.second) % Mod;
			res = (res + Mod) % Mod;
			printf("%d\n", res);
		}
		else
		{
			int u, v, w;
			scanf("%d%d%d", &u, &v, &w);
			Update_path(u, v, w);
		}
	}
	
	return 0;
}

posted @ 2020-08-27 15:51  Luckyblock  阅读(196)  评论(3编辑  收藏  举报