• 20201115gryz模拟赛解题报告


    写在前面

    T1:期望100pts,实际0pts(7:50 ~ 8:50

    T2:期望0pts,实际0pts(10:00 ~ 10:35

    T3:期望20pts,实际40pts( 9:10 ~ 10:00,10:35 ~ 11:00

    排名:rank2/10

    感觉今天状态好多了~ >-<!

    今天修树剖太累了,先咕咕咕,有空再把剩下两道题补上还有T3的满分代码,嘻嘻

    解题过程

    有了CSP的经验,先通读一遍题目,果断开T1,发现数的位数比较小,感觉暴力可以过,但是全排列不会写,发现贪心好像更简单,胡乱搞了两下,过了样例,判了前导零

    感觉没问题了,去吃了四楼顿饭,接着开T2,手模样例 + 乱搞,以为是个找规律,好像并不会做,暴力也不会打,

    决定先打T3暴力,读过一遍题目,发现这就是个裸树剖,算着暴力会T,为了骗分,暴力搞上再说,此时刚好打9:30下课铃,9:50,上课铃响,稍微一调,过了样例

    (我直接感动哭了,树剖从来没有打这么快过,还没有写挂)

    继续手模T2,没整明白,后来想T3优化也不成,最后五分钟发现T1忘记判负了,懒得改了~

    (后来发现T1没负数,我贪心贪错了

    正解

    T1

    题面

    Solution

    暴力枚举全排列,复杂度最多 (10 imes 9!) , 轻松A掉

    Talk is cheap,show me the code:

    next_permutation函数不太会用啊,调了一下午树剖,太累了,懒得写了

    我的贪心(不忍直视

    #include<iostream>
    #include<cstdio>
    #include<string>
    #include<cstring>
    
    using namespace std;
    
    int T, k;
    string s1, s2;
    
    int read(){
    	int s = 0, w = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
    	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
    	return s * w;
    }
    
    int main(){
    	//freopen("cooperate.in","r",stdin);
    	//freopen("cooperate.out","w",stdout);
    	T = read();
    	while(T--){
    		cin>>s1; k = read();
    		s2 = s1;
    		int len = s1.size(), wz, k2 = k;
    		//最大值
    		for(int i = 0; i < len; ++i){
    			wz = i;
    			for(int j = i + 1; j < len; ++j){
    				if(s1[i] < s1[j] && s1[wz] < s1[j]){
    					wz = j;
    				}
    			}
    			if(wz != i && k){
    				int x = s1[i];
    				s1[i] = s1[wz]; s1[wz] = x;
    				k--;
    			}
    		}
    		//最小值
    		wz = 0;
    		for(int j = 1; j < len; ++j){//最小值需要考虑不能有前导零,只要保证第一位不是就好了
    			if(s2[0] > s2[j] && s2[wz] >= s2[j] && s2[j] != '0'){
    				wz = j;
    			}
    		}
    		if(wz != 0 && k2){
    			int x = s2[0];
    			s2[0] = s2[wz], s2[wz] = x;
    			k2--;
    		}
    		
    		for(int i = 1; i < len; ++i){
    			wz = i;
    			for(int j = i + 1; j < len; ++j){
    				if(s2[i] > s2[j] && s2[wz] >= s2[j]){
    					wz = j;
    				}
    			}
    			if(wz != i && k2){
    
    				int x = s2[i];
    				s2[i] = s2[wz], s2[wz] = x;
    				k2--;
    			}
    		}
    		int sum1 = 0, sum2 = 0;
    		for(int i = 0; i < len; ++i){
    			sum1 = (sum1 << 1) + (sum1 << 3) + s1[i] - '0';
    			sum2 = (sum2 << 1) + (sum2 << 3) + s2[i] - '0';
    		}
    		// cout<<sum1<<endl<<sum2<<endl;
    		printf("%d
    ", sum1 - sum2);
    	}
    	return 0;
    }
    
    /*
    8
    12 1
    213 2
    998244350 1
    998244350 2
    998244353 1
    998244353 2
    998244353 3
    998244353 300
     */
    
    

    T2

    题面

    Solution

    把整个区间分成 (k (或者 k + 1)) 份,发现翻转两次就能使两盏处在同一位置的灯都点亮,

    然后……然后还没看呢

    T3

    题面

    solution

    这好像是今天唯一的成果

    裸的树剖,在求和是注意优化, (n ^ 2) 暴力只有20pts

    sbw给出了优化方案(O(n)遍历所有边求和,70pts:

    [ans_x = sum_{j in son_x} w_j * (siz_x - siz_j) * siz_j mod 2019 ]

    Talk is cheap,show me the code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    
    using namespace std;
    const int MAXN = 5e4+5;
    const int mod = 2019;
    
    int n, Q, cnt;
    int dfn[MAXN], pre[MAXN], fath[MAXN], son[MAXN], dep[MAXN], top[MAXN], siz[MAXN], a[MAXN], rd[MAXN];
    
    int read(){
    	int s = 0, w = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
    	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
    	return s * w;
    }
    
    namespace Seg{
    	#define lson i << 1
    	#define rson i << 1 | 1
    	struct Tree{
    		int sum, lazy, len;
    	}tree[MAXN << 2];
    	void push_up(int i){
    		tree[i].sum = (tree[lson].sum + tree[rson].sum) % mod;
    	}
    	void push_down(int i){
    		if(tree[i].lazy){
    			tree[lson].lazy = (tree[lson].lazy + tree[i].lazy) % mod;
    			tree[rson].lazy = (tree[rson].lazy + tree[i].lazy) % mod;
    			tree[lson].sum = (tree[lson].sum + tree[i].lazy * tree[lson].len) % mod;
    			tree[rson].sum = (tree[rson].sum + tree[i].lazy * tree[rson].len) % mod;
    			tree[i].lazy = 0;
    		}
    	}
    	void build(int i, int l, int r){
    		tree[i].lazy = 0, tree[i].len = r - l + 1;
    		if(l == r){
    			tree[i].sum = a[pre[l]] % mod;
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		build(lson, l, mid), build(rson, mid + 1, r);
    		push_up(i);
    		return ;
    	}
    	void add(int i, int l, int r, int L, int R, int k){
    		if(L <= l && r <= R){
    			tree[i].sum = (tree[i].sum + tree[i].len * k) % mod;
    			tree[i].lazy = (tree[i].lazy + k) % mod;
    			return ;
    		}
    		push_down(i);
    		int mid = (l + r) >> 1;
    		if(mid >= L) add(lson, l, mid, L, R, k);
    		if(mid < R) add(rson, mid + 1, r, L, R, k);
    		push_up(i);
    		return ;
    	}
    	int get_sum(int i, int l, int r, int L, int R){
    		if(L <= l && r <= R){
    			return tree[i].sum % mod;
    		}
    		push_down(i);
    		int mid = (l + r) >> 1, ans = 0;
    		if(mid >= L) ans = (ans + get_sum(lson, l, mid, L, R)) % mod;
    		if(mid < R) ans = (ans + get_sum(rson, mid + 1, r, L, R)) % mod;
    		return ans % mod;
    	}
    }
    
    namespace Cut{
    	struct edge{
    		int to, w, nxt;
    	}e[MAXN << 1];
    	int head[MAXN], num_edge = 0;
    	void add_edge(int from, int to, int w){
    		e[++num_edge] = (edge){to, w, head[from]}, head[from] = num_edge;
    	}
    	void dfs(int x, int fa){
    		siz[x] = 1, dep[x] = dep[fa] + 1, fath[x] = fa;
    		for(int i = head[x]; i; i = e[i].nxt){
    			int v = e[i].to;
    			if(v == fa) continue;
    			dfs(v, x);
    			siz[x] += siz[v];
    			if(siz[v] > siz[son[x]]) son[x] = v; 
    		}
    	}
    	void dfs2(int x, int tp){
    		dfn[x] = ++cnt, pre[cnt] = x, top[x] = tp;
    		if(son[x]) dfs2(son[x], tp);
    		for(int i = head[x]; i; i = e[i].nxt){
    			int v = e[i].to;
    			if(v == fath[x] || v == son[x]) continue;
    			dfs2(v, v);
    		}
    	}
    	void change(int x, int y, int k){
    		while(top[x] != top[y]){
    			if(dep[top[x]] < dep[top[y]]) swap(x, y);
    			Seg::add(1, 1, n, dfn[top[x]], dfn[x], k);
    			x = fath[top[x]];
    		}
    		if(dfn[x] > dfn[y]) swap(x ,y);
    		Seg::add(1, 1, n, dfn[x] + 1, dfn[y], k);
    		return ;
    	}
    	int get(int x, int y){
    		int ans = 0;
    		while(top[x] != top[y]){
    			if(dep[top[x]] < dep[top[y]]) swap(x, y);
    			ans = (ans + Seg::get_sum(1, 1, n, dfn[top[x]], dfn[x])) % mod;
    			x = fath[top[x]];
    		}
    		if(dfn[x] > dfn[y]) swap(x, y);
    		ans = (ans + Seg::get_sum(1, 1, n, dfn[x] + 1, dfn[y])) % mod;
    		return ans % mod;
    	}
    	int get_s(int x, int rt){//O(n)遍历所有边求和,正解,100pts
    		int ans = 0;
    		for(int i = head[x]; i; i = e[i].nxt){
    			int v = e[i].to;
    			if(v == fath[x]) continue;
    			ans = (ans + Seg::get_sum(1, 1, n, dfn[v], dfn[v]) % mod * (siz[rt] - siz[v]) % mod * siz[v]) % mod;
    			ans = (ans + get_s(v, rt)) % mod;
    		}
    		return ans;
    	}
    	int get_ss(int x){//暴力,枚举所有情况求和,只有40pts
    		int ans = 0;
    		for(int i = dfn[x]; i < dfn[x] + siz[x] - 1; ++i){
    			for(int j = i + 1; j <= dfn[x] + siz[x] - 1; ++j){
    				ans = (ans + get(pre[i], pre[j])) % mod;
    			}
    		}
    		return ans;
    	}
    }
    
    int main(){
    	//freopen("network.in","r",stdin);
    	//freopen("network.out","w",stdout);
    	n = read(), Q = read();
    	for(int i = 2, u; i <= n; ++i){
    		u = read(), a[i] = read();
    		Cut::add_edge(u, i, a[i]), Cut::add_edge(i, u, a[i]);
    		rd[i]++;
    	}
    	
    	int wz;
    	for(int i = 1; i <= n; ++i) if(!rd[i]) {wz = i; break; }
    	
    	Cut::dfs(wz, 0), Cut::dfs2(wz, wz), Seg::build(1, 1, n);
    	
    	for(int i = 1, x, y, k; i <= Q; ++i){
    		string s;
    		cin>>s;
    		if(s[0] == 'I'){
    			x = read(), y = read(), k = read();
    			Cut::change(x, y, k);
    		}
    		if(s[0] == 'A'){
    			x = read();
    			// printf("%d
    ", Cut::get_ss(x) % mod);
    			printf("%d
    ", Cut::get_s(x, x) % mod);
    		}
    	}
    	return 0;
    }
    /*
    5 5
    1 1
    2 5
    1 2
    2 1
    INC 2 4 2
    INC 3 4 1
    ASK 2
    INC 2 5 3
    ASK 1
     */
    
  • 相关阅读:
    终于想起了博客园密码
    关于GCD的8题
    idea快捷键 ctrl + shift + f 失效解决方法
    前端和后端日期类型交互
    poi、easypoi和easyexcel的使用
    事务总结
    数据库cte的理解和使用
    mybatis 调用存储过程没有返回值
    postgresql 查询锁表并解锁
    tigase网络核心SockThread详解(十九)
  • 原文地址:https://www.cnblogs.com/Silymtics/p/13978732.html
Copyright © 2020-2023  润新知