zoukankan      html  css  js  c++  java
  • 1026考试总结

    1026考试总结

    T1

    ​ 题目大意:

    ​ 给定一个整数(n),有另外三个整数(l, w, h)满足(l mid n, w mid n, h mid n)并且(l + w + h = n),求最大的(l * w * h).(没有满足条件的输出-1)有多组数据(T <= 1e6, n <= 1e6).

    ​ 首先这个式子(l + w + h = n)可以化成(frac{1}{n / l} + frac{1}{n / w} + frac{1}{n / h} = 1).

    ​ 然后我们可以想到满足条件的等式(frac{1}{2} + frac{1}{3} + frac{1}{6} = 1(6的倍数), frac{1}{3} + frac{1}{3} + frac{1}{3} = 1(3的倍数), frac{1}{2} + frac{1}{4} + frac{1}{4} = 1(4的倍数)).

    ​ 对于一个长方体,它的长宽高尽量接近时,它的体积最大,我不会证.显然上面那三个等式第一个没第二个优.

    ​ 然后直接判断(n)是否是3,4的倍数,如果不是其他情况输出-1就好了.复杂度(O(T)).

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
    	long long s = 0, f = 1; char ch;
    	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    	return s * f;
    }
    
    int t, n;
    
    int main() {
    	
    	t = read();
    	while(t --> 0) {
    		n = read();
    		if(n % 3 == 0) printf("%lld
    ", 1ll * n * n * n / 27); 
    		else if(n % 4 == 0) printf("%lld
    ", 1ll * n * n * n / 32);
    		else printf("-1
    ");
    	}
    	
    	return 0;
    }
    

    T2

    ​ 题目大意:

    ​ 勇士有K个属性 , 大小分别为v[1],v[2],…,v[K],一共有 N 只怪物,每只怪物也有相应的 K 个属性,第 i 只怪物的第 j 项属性标记为 a[i][j]。若对于任意的j(1≤j≤K)都有a[i][j]≤v[j],则勇士可以干掉第 i 只怪物,而且干掉第 i 只怪物后,勇士的各项属性都会得到提升,其中第 j 项属性的提升了 b[i][j]。按照最优策略来打怪,最多能干掉多少只怪物。

    ​ 多组数据(T <= 5), (n <= 1e5).(k <= 5).

    ​ 发现(k)很小,我们可以开5个小根堆,按顺序判断每个怪物的第(k)个属性,假设当先堆顶的这个属性小于等于勇士的第(k)的属性,那么就在第(k + 1)个属性的小根堆里加入这个怪物.如果说某一个怪物咋第(5)个堆出队,那么说明他的所有属性都小于等于勇士的属性,那么把它统计到答案里面就好了,别忘了提升勇士本身的属性.

    ​ 因为每个节点最多进堆(k)次,所以复杂度(O(nlog n * k)).

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
    	long long s = 0, f = 1; char ch;
    	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    	return s * f;
    }
    
    const int N = 1e5 + 5;
    int t, n, k, ans;
    struct node { int s[6], u[6]; } a[N];
    priority_queue <pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q[6];
    
    int main() {
    	
    	t = read();
    	while(t --> 0) {
    		n = read(); k = read(); ans = 0;
    		for(int i = 1;i <= k; i++) a[0].s[i] = read();
    		for(int i = 1;i <= n; i++) {
    			for(int j = 1;j <= k; j++) a[i].s[j] = read();
    			for(int j = 1;j <= k; j++) a[i].u[j] = read();
    		}
    		for(int i = 1;i <= k; i++) while(q[i].size()) q[i].pop();
    		for(int i = 1;i <= n; i++) q[1].push(make_pair(a[i].s[1], i));
    		while(1) {
    			int tag = 0;
    			for(int i = 1;i <= k; i++) {
    				while(q[i].size() && q[i].top().first <= a[0].s[i]) {
    					int tmp = q[i].top().second; 
    					q[i].pop();
    					if(i < k) q[i + 1].push(make_pair(a[tmp].s[i + 1], tmp));
    					if(i == k) {
    						ans ++, tag = 1;
    						for(int j = 1;j <= k; j++) a[0].s[j] += a[tmp].u[j];
    					}
    				}
    			}
    			if(!tag) break;
    		}
    		printf("%d
    ", ans);
    		for(int i = 1;i <= k; i++) printf("%d ", a[0].s[i]);
    		printf("
    ");
    	}
    	
    	return 0;
    }
    

    T3

    ​ 题目大意:
    ​ 已知全班共有 N 位同学报名参加趣味运动会,小 Z 需要在这 N 位同学中选出若干对同学,组队参加二人三足。可惜的是,这 N 位同学之间总是小摩擦不断,说不准昨天 A 和 B 吵架了,不再适合组队,而没过多久,前天吵架的 C 和D 就又突然和好了。小 Z 得知这 N 位同学的吵架及和好事件的发生,他好奇每发生一次吵架或和好后,派出 k 组同学参加二人三足的方案数,分别是多少。其中 k=1,2,……,N/2。

    ​ 第一行为测试数据组数 T(1≤T≤10)。每组测试数据的第一行为学生数量 N 及事件数 M。其中 N (N <= 10)为偶数。接下来 M (M <= 30000)行,第 i 行通过一个三元组 c u v 描述一个事件,其中 c 为字符,要么是“+”要么是“-”,而 u 和 v 为吵架(用“-”表示)或和好(用“+”表示)的两位同学的编号。数据保证两位刚和好的同学之前处于吵架状态,而刚吵架的同学之前处于和好状态。

    ​ 状压DP.

    (f[i][s])表示前i次操作后状态为s(1表示可能与别人组队的人,也就是至少有一个人与他和好)的方案数是多少.那么DP转移方程就是:

    (f[i][s] = f[i - 1][s] + f[i - 1][s xor (1 << x) xor (1 << y)]).((x, y)代表第(i)次操作的和好的两个人,如果是吵架的两个人那么就把中间的加好改成减号就好了).

    ​ 复杂度(O(m * 2 ^ n)).

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
    	long long s = 0, f = 1; char ch;
    	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    	return s * f;
    }
    
    const int N = 11, mod = 1e9 + 7;
    int t, n, m; 
    char ch;
    int f[30001][1 << N], ans[6], num[1 << N];
    
    int main() {
    	
    	t = read();
    	for(int i = 0;i < (1 << 10); i++) num[i] = num[i >> 1] + (i & 1);
    	while(t --> 0) {
    		n = read(); m = read();
    		for(int i = 1;i <= n; i++) 
    			for(int j = 0;j < (1 << n); j++) f[i][j] = 0;
    		f[0][0] = 1;
    		for(int i = 1, x, y;i <= m; i++) {
    			cin >> ch; x = read() - 1; y = read() - 1;
    			for(int j = 1;j <= n / 2; j++) ans[j] = 0;
    			int tmp = (1 << x) | (1 << y);
    			if(ch == '+') {
    				for(int j = 0;j < (1 << n); j++) {
    					f[i][j] = f[i - 1][j];
    					if((tmp & j) == tmp) (f[i][j] += f[i - 1][j ^ tmp]) %= mod;
    					(ans[num[j] / 2] += f[i][j]) %= mod;
    				}
    			}
    			if(ch == '-') {
    				for(int j = 0;j < (1 << n); j++) {
    					f[i][j] = f[i - 1][j];
    					if((tmp & j) == tmp) ((f[i][j] -= f[i - 1][j ^ tmp]) += mod) %= mod;
    					(ans[num[j] / 2] += f[i][j]) %= mod;
    				}
    			}
    			for(int i = 1;i <= n / 2; i++) printf("%d ", ans[i]);
    			printf("
    ");
    		}
    	}
        
    	return 0;
    }
    
  • 相关阅读:
    最小树形图 朱刘算法模板+建边技巧
    模板倍增LCA 求树上两点距离 hdu2586
    【瞎搞题】gym226123 L. For the Honest Election
    【凸包板题】Gym
    集合3
    集合2
    集合1
    常用API&异常
    内部类&API
    多态&接口类&接口
  • 原文地址:https://www.cnblogs.com/czhui666/p/13881446.html
Copyright © 2011-2022 走看看