zoukankan      html  css  js  c++  java
  • 20201103gryz模拟赛解题报告

    写在前面

    昨天忘写了来补上

    T1位运算乱搞一会没搞出来,

    打完T4floyd暴力分之后发现T2树状数组可以骗点分

    打完T3暴力手模了一遍样例之后发现T3就是个线段树板子

    最后就非常愉快的拿到175pts,rank3

    T1:U139249 位运算之谜

    https://i.cnblogs.com/preference

    很显然我并不知道这个公式

    因为a&b表示的是都是1的位数,a^b表示的是只有一个是1的位数,

    如果都是1,a+b后会进位,否则保留,

    所以可推的如上的式子:$a+b=((a&b)<<1)+(a^b) $;

    由题意已知(a&b=y)(a+b=x)

    (a^b=x-2 imes y);

    因为这个数取的是不同位,(y)取的是相同位,所以他俩(&)起来一定为(0)

    不为 (0) 为不合法

    /*
    Work by: Suzt_ilymics
    Knowledge: ??
    Time: O(??)
    */
    #include<iostream>
    #include<cstdio>
    using namespace std;
    long long T, x, y;
    
    long long read(){
    	long long w = 1, s = 0;
    	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()
    {
    	T = read();
    	while(T--){
    		x = read(), y = read();
    		if((x - 2 * y) < 0 || ((x - 2 * y) & y)) cout<<-1<<endl;
    		else cout<<(x - y - y)<<endl;
    	}	
    	return 0;
    }
    

    T2:U139245 游戏

    看到数据范围比较小,预处理一个二维前缀和

    暴力枚举每个节点i,j,二分找出最长边长即可

    二维树状数组的话还是太慢了

    /*
    Work by: Suzt_ilymics
    Knowledge: ??
    Time: O(??)
    */
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n, m, K;
    int sum[310][310][30];
    int a[310][310][30];
    
    int read(){
    	int w = 1, s = 0;
    	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;
    }
    
    bool check(int i, int j, int k, int l){
    	for(int a = 1; a <= 26; ++a){
    		if(sum[k][l][a] + sum[i - 1][j - 1][a] - sum[i - 1][l][a] - sum[k][j - 1][a] > K) return false;
    	}
    	return true;
    }
    
    int main()
    {
    	n = read(), m = read(), K = read();
    	char x;
    	for(int i = 1; i <= n; ++i){
    		for(int j = 1; j <= m; ++j){
    			cin>>x;
    			a[i][j][x - 'a' + 1]++;
    			for(int k = 1; k <= 26; ++k){
    				sum[i][j][k] = sum[i-1][j][k] + sum[i][j-1][k] - sum[i-1][j-1][k] + a[i][j][k];
    			}
    		}
    	}
    	for(int i = 1; i <= n; ++i){
    		for(int j = 1; j <= m; ++j){
    			int l = 0, r = min(n - i, m - j), ans = 0;
    			while(l <= r){
    				int mid = (l + r) >> 1;
    				if(check(i, j, i + mid, j + mid)){ ans = mid; l = mid + 1; }
    				else{ r = mid - 1; }
    			}
    			printf("%d ", ans + 1);
    		}
    		puts("");
    	}
    	return 0;
    }
    
    

    T3:U139247 或和异或

    手模样例发现每两个相邻的元素在每次操作后会合并成一个

    可以用线段树来维护一下,最后输出树根的答案即可

    修改操作对应线段树的单点修改

    上传的时候注意判断是or还是xor

    /*
    Work by: Suzt_ilymics
    Knowledge: ??
    Time: O(??)
    =============================Kersen AK IOI !!!=====================================================
    */
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define lson i << 1
    #define rson i << 1 | 1
    using namespace std;
    const int MAXN = 131100;
    struct Tree{
    	long long dep;
    	long long sum;
    }tree[MAXN << 2];
    long long n, Q;
    bool flag = 0;
    long long a[131080];
    int ecm[20] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072};
    //long long b[131080];
    //int wzd[30];
    //long long kersen[30];
    
    long long read(){
    	long long 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;
    }
    
    void push_up(int i){
    	if(!flag){//如果n是奇数,树是n + 1层,上传的时候奇数深度进行|操作,偶数深度进行^操作 
    		if(tree[i].dep % 2){tree[i].sum = (tree[lson].sum | tree[rson].sum);}
    		else{tree[i].sum = (tree[lson].sum ^ tree[rson].sum);}
    	}
    	else{//如果n是偶数,树是n + 1层,上传的时候偶数深度进行|操作,奇数深度进行^操作,与上面相反 
    		if(tree[i].dep % 2){tree[i].sum = (tree[lson].sum ^ tree[rson].sum);}
    		else{tree[i].sum = (tree[lson].sum | tree[rson].sum);}
    	}
    }
    
    void build(long long i, long long l, long long r, long long dep){
    	tree[i].dep = dep;
    	if(l == r) {
    		tree[i].sum = a[l];
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build(lson, l, mid, dep + 1), build(rson, mid + 1, r, dep + 1);
    	push_up(i);
    	return ;
    }
    
    void add(long long i ,long long l, long long r, long long x, long long k){
    	if(l == x && r == x) {
    		tree[i].sum = k;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if(x <= mid) add(lson, l, mid, x, k);
    	else add(rson, mid + 1, r, x, k);
    	push_up(i);
    	return ;
    }
    
    int main()
    {
    //	freopen("xor.in","r",stdin);
    //	freopen("xor.out","w",stdout);
    	n = read(), Q = read();
    	if(n%2 == 0) flag = 1;//如果n是偶数,标记一下 
    	for(long long i = 1; i <= ecm[n]; ++i) a[i] = read();
    	build(1, 1, ecm[n], 1);
    	for(long long i = 1, x, k; i <= Q; ++i){
    		x = read(), k = read();
    		add(1, 1, ecm[n], x, k);
    		cout<<tree[1].sum<<endl;
    	}
    	return 0;
    }
    
    

    T4:U139253 链接

    因为边的长度随编号的增加而增加,且前i条边的和一定不会超过第i+1条边

    根据这个性质,在读入边的时候直接建出最小生成树,就求完了各个点的最短路

    考虑u,v这两个节点 ,假设我们已经知道了u,那么我们可以通过如下式子推得v

    [ans_{v} = ans_{u} - siz_{v} imes e_{i}.w + (point - siz_{v}) imes e_{i}.w ]

    最后求一下和就是答案

    /*
    Work by: Suzt_ilymics
    Knowledge: ??
    Time: O(??)
    */
    #include<iostream>
    #include<cstdio>
    #define int long long
    using namespace std;
    const int MAXN = 1e5+5;
    const int MAXM = 2e5+5;
    const int mod = 1000000007;
    struct edge{
    	int to, w, nxt;
    }e[MAXM];
    int head[MAXN], num_edge;
    int n, m, point;
    int dis[MAXN], fath[MAXN], f[MAXN], siz[MAXN];
    bool type[MAXN];
    
    int read(){
    	int w = 1, s = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
    	while(ch >= '0' && ch <= '9') s = s* 10 + ch - '0', ch = getchar();
    	return s * w;
    }
    //bool read1(){
    //	bool s = 0;
    //	char ch = getchar();
    //	while(ch >= '0' && ch <= '9') s = s* 10 + ch - '0', ch = getchar();
    //	return s;
    //}
    
    void add(int from, int to, int w){
    	e[++num_edge].to = to;
    	e[num_edge].w = w;
    	e[num_edge].nxt = head[from];
    	head[from] = num_edge;
    } 
    
    int find(int x){return fath[x] == x ? x : fath[x] = find(fath[x]); }
    
    void dfs(int x, int fa){
    	for(int i = head[x]; i; i = e[i].nxt){
    		int v = e[i].to;
    		if(v == fa) continue;
    		dis[v] = (dis[x] + e[i].w) % mod;
    		dfs(v, x), siz[x] += siz[v];
    	}
    }
    
    void dfs2(int x, int fa){
    	for(int i = head[x]; i; i = e[i].nxt){
    		int v = e[i].to;
    		if(v == fa) continue;
    		int jia = ((point - siz[v]) % mod + mod) % mod;
    		int jian = siz[v] * e[i].w % mod;
    		jia = (jia * e[i].w) % mod;
    		f[v] = ((f[x] + jia - jian) % mod + mod) % mod;
    		dfs2(v, x); 
    	}
    }
    
    signed main()
    {
    	n = read(), m = read();
    	bool flag = 0, se = 0;
    	se = read();
    	if(se) flag = 1, type[1] = se ^ 1;
    	else type[1] = 0;
    	for(int i = 2; i <= n; ++i){
    		type[i] = read();
    //		cin>>type[i];
    		if(flag) type[i] = (type[i] ^ 1);
    		siz[i] = type[i];//顺便处理在以i为根的子树中,与1节点不同的点的个数 
    	}
    	for(int i = 1; i <= n; ++i) fath[i] = i;
    	int x = 2, cnt = 0;
    	for(int i = 1, u, v; i <= m; ++i){
    		u = read(), v = read();
    		int uf = find(u), vf = find(v);
    		if(uf != vf){
    			fath[uf] = vf;
    			add(u, v, x), add(v, u, x);
    			//cnt++;
    		}
    //			if(++cnt == n - 1) break;
    		x = (x * 2) % mod;
    	}
    	dfs(1, 1), point = siz[1];
    	for(int i = 1; i <= n; ++i){
    		if(type[i]) f[1] = (f[1] + dis[i]) % mod;//先暴力把1与其他点的权值和加起来 
    	} 
    	dfs2(1, 1);
    	int ans = 0;
    	for(int i = 1; i <= n; ++i){
    		if(!type[i]) ans = (ans + f[i]) % mod;
    	}
    	printf("%d", ans);
    	return 0;
    }
    
    
  • 相关阅读:
    (转)MVC 与三层架构
    (转)CentOS一键安装Nginx脚本
    (转)Python异常类的继承关系
    CMFCPropertyGridProperty用法
    C语言终极面试及答案分析
    C/C++函数指针(typedef简化定义)
    UNIX 家族及Linux
    Socket的综合应用总结
    Socket模型(二):完成端口(IOCP)
    socket通信中select函数的使用和解释
  • 原文地址:https://www.cnblogs.com/Silymtics/p/13926634.html
Copyright © 2011-2022 走看看