• AHU 周末练习 题解


    =。= 这次比赛乱搞题比较多。。做的时候也比较烦躁。。感觉效率不是很高。

    A: 水题,直接记录每个数字的位置然后输出就好了。

    B:  题目看半天才明白,其实就是考一个三进制转化,很水。。

    typedef long long LL;
    const int maxn = 1024;
    int numa[maxn], numc[maxn], numb[maxn];
    
    int to3(LL num, int *str) {
    	int len = 0;
    	while(num) {
    		str[len++] = num % 3;
    		num /= 3;
    	}
    	return len;
    } 
    
    int main() {
    	int a, b, c;
    	cin >> a >> c;
    	int lena = to3(a, numa);
    	int lenc = to3(c, numc);
    	int lenb = max(lena, lenc);
    	for(int i = 0; i < lenb; i++) {
    		numb[i] = (numc[i] - numa[i]) % 3 + 3;
    		numb[i] %= 3;
    	}
    	int ans = 0;
    	for(int i = lenb - 1; i >= 0; i--) ans = ans * 3 + numb[i];
    	cout << ans << endl;
    	return 0;
    }
    

    C: 注意特判一下全部元素都是1的情况,这时候只能交换到2,其他情况都是把最大的数换成1

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <bitset>
    #include <queue>
    #include <stack>
    #include <string>
    #include <iostream>
    #include <cmath>
    #include <climits>
    
    using namespace std;
    const int maxn = 1e5 + 10;
    int num[maxn];
    
    int main() {
    	int n; cin >> n;
    	bool flag = false;
    	for(int i = 1; i <= n; i++) {
    		cin >> num[i];
    		if(num[i] != 1) flag = true;
    	}
    	if(!flag) {
    		for(int i = 1; i < n; i++) cout << "1 ";
    		cout << 2 << endl;
    		return 0;
    	}
    	num[0] = 1;
    	sort(num, num + n + 1);
    	for(int i = 0; i < n; i++) cout << num[i] << " ";
    	cout << endl;
    	return 0;
    }
    

    D: 题意是,给你八个点,问你能不能选出4个点使其构成正方形,剩下4个构成长方形。

    先枚举所有点的全排列,然后只要无脑判断前4个点和后四个点就好了。

    判断矩形只要判断相邻的边都垂直,正方形只要在这基础上保证四条边都相等就好。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    struct Point {
    	double x, y;
    	Point(double x, double y) :x(x), y(y) {}
    	Point() {};
    };
    
    Point operator - (Point a, Point b) {
    	return Point(a.x - b.x, a.y - b.y);
    }
    
    double dist(Point a) {
    	return sqrt(a.x*a.x + a.y*a.y);
    }
    
    double ag(Point a, Point b) {
    	return fabs(a.x*b.x + a.y*b.y);
    }
    
    const double eps = 1e-7;
    Point p[10];
    int id[10];
    
    bool equ(double a, double b) {
    	if (fabs(a - b) < eps) return true;
    	return false;
    }
    
    bool isSquare(Point a1, Point a2, Point a3, Point a4) {
    	Point p1 = a1 - a2, p2 = a2 - a3, p3 = a3 - a4, p4 = a4 - a1;
    	double app = ag(p1, p2) + ag(p2, p3) + ag(p3, p4) + ag(p4, p1);
    	if (fabs(app) > eps) return false;
    	if (equ(dist(p1), dist(p2)) && equ(dist(p1), dist(p3)) && equ(dist(p1), dist(p4)))
    		return true;
    	return false;
    }
    
    bool isR(Point a1, Point a2, Point a3, Point a4) {
    	Point p1 = a1 - a2, p2 = a2 - a3, p3 = a3 - a4, p4 = a4 - a1;
    	double app = ag(p1, p2) + ag(p2, p3) + ag(p3, p4) + ag(p4, p1);
    	if (fabs(app) > eps) return false;
    	return true;
    }
    
    int main() {
    	for (int i = 1; i <= 8; i++) {
    		scanf("%lf%lf", &p[i].x, &p[i].y);
    		id[i] = i;
    	}
    	do {
    		bool r1 = isSquare(p[id[1]], p[id[2]], p[id[3]], p[id[4]]);
    		bool r2 = isR(p[id[5]], p[id[6]], p[id[7]], p[id[8]]);
    		if (r1 && r2) {
    			puts("YES");
    			printf("%d %d %d %d
    ", id[1], id[2], id[3], id[4]);
    			printf("%d %d %d %d
    ", id[5], id[6], id[7], id[8]);
    			return 0;
    		}
    	} while (next_permutation(id + 1, id + 1 + 8));
    	puts("NO");
    	return 0;
    }
    

    E: 题意是:给你一个01?序列,有两个人先后从序列中取数字,直到只剩两个数字的时候。先手的人想让剩下的数字尽可能小,后手的人想让数字尽可能的大。问?取01任意情况的时候,最后剩下的两位数的所有可能性。

    考虑没有问号的情况,设cnt0为0的数量,cnt1为1的数量。

    有如果cnt0 > cnt1 必为 00

    cnt1 > cnt0 + 1 必为11

    cnt1 == cnt0 或者 cnt1 == cnt0 + 1 的时候可能10也可能01,最后的值由序列的最后一个元素的决定。

    那么加上问号之后 有cnt2表示问号的数量

    如果可能达到cnt0+cntw>cnt1 00是有可能出现的

    如果可能达到cnt1 + cntw > cnt0 + 1 11是有可能出现的

    然后如果可能出现一种情况使得加上问号之后有cnt1==cnt0或者cnt1==cnt0+1,并且序列的最后一位不是问号,那么10或者01中的一个是可能出现的。

    如果序列最后一个数是问号,那么分别讨论这个问号是0和1的情况,并且重新判断加上cnt2-1个问号之后,cnt1==cnt0,cnt1==cnt0+1是否可能达到。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <bitset>
    #include <queue>
    #include <stack>
    #include <string>
    #include <iostream>
    #include <cmath>
    #include <climits>
    
    using namespace std;
    const int maxn = 2e5 + 10;
    char buf[maxn];
    
    void gao(char *str) {
    	int len = strlen(str);
    	int cnt0 = 0, cnt1 = 0, cntw = 0;
    	for(int i = 0; i < len; i++) {
    		if(str[i] == '0') cnt0++;
    		if(str[i] == '1') cnt1++;
    		if(str[i] == '?') cntw++;
    	}
    	if(cnt0 + cntw > cnt1) puts("00");
    	if(cnt0 + cntw + 1 >= cnt1 && cnt1 + cntw >= cnt0) {
    		if(str[len - 1] == '?') {
    			//假设最后一位填1
    			if(cnt0 + cntw >= cnt1 + 1 && cnt1 + cntw >= cnt0) puts("01");
    			//假设最后一位填0
    			if(cnt0 + cntw + 1 >= cnt1 && cnt1 + cntw - 1 >= cnt0 + 1) puts("10");
    
    		}
    		else if(str[len - 1] == '1') puts("01");
    		else puts("10");
    	}
    	if(cnt1 + cntw > cnt0 + 1) puts("11");
    }
    
    int main() {
    	while(scanf("%s", buf) != EOF) {
    		gao(buf);
    	}
    	return 0;
    }
    

    F 题意是战场上有n个横向或者纵向的沟壑,每a秒会有激光扫射战场b秒,人的移动速度是1,问你能否从起点到达终点。。保证b大于任意一个沟壑长度。

    先预处理出来所有沟壑之间的距离,然后bfs一遍就好了,因为只要距离小于a,时间肯定是a。

    bfs可以用优先队列加速一下~

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <bitset>
    #include <queue>
    #include <stack>
    #include <string>
    #include <iostream>
    #include <cmath>
    #include <climits>
    
    using namespace std;
    const int maxn = 1e3 + 10;
    const double eps = 1e-9;
    
    int a, b, n;
    double sx, sy, ex, ey;
    double dist[maxn][maxn];
    double posx1[maxn], posx2[maxn], posy1[maxn], posy2[maxn];
    bool vis[maxn];
    
    bool equ(double a, double b) {
    	return fabs(a - b) < eps;
    }
    
    struct Point {
    	double x, y;
    	Point (double x = 0, double y = 0):
    		x(x), y(y) {}
    	bool operator == (const Point &p) const {
    		return equ(p.x, x) && equ(p.y, y);
    	}
    };
    
    typedef Point Vector;
    
    double sq(double x) {
    	return x * x;
    }
    
    Point operator - (Point a, Point b) {
    	return Point(a.x - b.x, a.y - b.y);
    } 
    
    double getdist(Vector v) {
    	return sqrt(v.x * v.x + v.y * v.y);
    }
    
    double dot(Vector a, Vector b) {
    	return a.x * b.x + a.y * b.y;
    }
    
    double Cross(Vector a, Vector b) {
    	return a.x * b.y - a.y * b.x;
    }
    
    double getdist(Point p, Point a, Point b) {
    	if(a == b) return getdist(p - a);
    	Vector v1 = b - a, v2 = p - a, v3 = p - b;
    	if(dot(v1, v2) < 0) return getdist(v2);
    	else if(dot(v1, v3) > 0) return getdist(v3);
    	else return fabs(Cross(v1, v2)) / getdist(v1);
    }
    
    double getdist(int i, int j) {
    	//判断两条线段的距离
    	double x1 = posx1[i], x2 = posx2[i], y1 = posy1[i], y2 = posy2[i];
    	double x3 = posx1[j], x4 = posx2[j], y3 = posy1[j], y4 = posy2[j];
    	Point p1(x1, y1), p2(x2, y2), p3(x3, y3), p4(x4, y4);
    	double ret = min(getdist(p1, p3, p4), getdist(p2, p3, p4));
    	ret = min(ret, min(getdist(p3, p1, p2), getdist(p4, p1, p2)));
    	return ret;
    }
    
    struct Node {
    	int id; double cost;
    	Node(int id = 0, double cost = 0):
    		id(id), cost(cost) {}
    	bool operator < (const Node &x) const {
    		return cost > x.cost;
    	}
    };
    
    int main() {
    	scanf("%d%d", &a, &b);
    	scanf("%lf%lf%lf%lf", &sx, &sy, &ex, &ey);
    	scanf("%d", &n);
    	posx1[0] = posx2[0] = sx;
    	posy1[0] = posy2[0] = sy;
    	posx1[n + 1] = posx2[n + 1] = ex;
    	posy1[n + 1] = posy2[n + 1] = ey;
    	for(int i = 1; i <= n; i++) {
    		scanf("%lf%lf%lf%lf", &posx1[i], &posy1[i], &posx2[i], &posy2[i]);
    	}
    	for(int i = 1; i <= n; i++) {
    		for(int j = 1; j <= n; j++) {
    			dist[i][j] = getdist(i, j);
    		}
    	}
    	//BFS
    	double pse = getdist(Point(sx, sy) -  Point(ex, ey));
    	double ans = pse <= a ? pse : 1e12;
    	priority_queue<Node> q;
    	for(int i = 1; i <= n; i++) {
    		double ret = getdist(0, i);
    		if(ret <= a) {
    			q.push(Node(i, a + b));
    		}
    	}
    	while(!q.empty()) {
    		Node tt = q.top(); q.pop();
    		int now = tt.id;
    		double nowcost = tt.cost;
    		//printf("%d %.3f
    ", now, nowcost);
    		if(getdist(now, n + 1) <= a) {
    			ans = min(ans, nowcost + getdist(now, n + 1));
    		}
    		for(int i = 1; i <= n; i++) if(dist[now][i] <= a + eps && !vis[i]) {
    			q.push(Node(i, nowcost + a + b));
    			vis[i] = true;
    		}
    	}
    	if(ans > 1e10) puts("-1");
    	else printf("%.10f
    ", ans);
    	return 0;
    }
    

      

    G:水题,直接搞。

    H: 题意是,给你一个序列,现在最多可以进行k次操作,每次操作可以让序列中任意一个元素取反,问你最大可能的长度为len的子序列和的绝对值是多少。

    考虑使用简单的滑窗模型,维护一个长度为len的子序列,每次只要增删一个值并且统计处理就可以了。

    现在需要的就是这样一个数据结构,

    可以快速增加和删除元素,可以快速的求前k大的和。

    其实用两个multiset就可以处理这样的问题。。或者用两个map模拟 multiset

    也可以用树状数组套主席树。。不过没必要吧。。

    具体看代码吧。。

    至于处理绝对值,只要把所有数字取反再算一遍就好了。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <bitset>
    #include <queue>
    #include <stack>
    #include <string>
    #include <iostream>
    #include <cmath>
    #include <climits>
    
    using namespace std;
    
    typedef long long LL;
    
    const int maxn = 1e5 + 10;
    
    multiset<int> st1, st;
    int n, len, k, a[maxn];
    LL sum = 0;
    
    void insert(int num) {
    	if (k == 0) {
    		sum -= num; return;
    	}
    	if (st.size() == k) {
    		int pnum = *st.begin();
    		if (pnum < num) {
    			st.erase(st.begin());
    			sum = sum - 2 * pnum + num;
    			st.insert(num);
    			st1.insert(pnum);
    		}
    		else {
    			st1.insert(num);
    			sum -= num;
    		}
    	}
    	else {
    		sum += num; st.insert(num);
    	}
    }
    
    void erase(int num) {
    	if (k == 0) {
    		sum += num; return;
    	}
    	multiset<int>::iterator it = st.find(num);
    	if (it != st.end()) {
    		st.erase(it); sum -= num;
    		if (st1.size() != 0) {
    			it = st1.end(); it--;
    			insert((*it));
    			sum += *it;
    			st1.erase(it);
    		}
    	}
    	else {
    		it = st1.find(num);
    		if(it != st1.end()) st1.erase(it);
    		sum += num;
    	}
    }
    
    LL gao() {
    	LL ans = 0;
    	st.clear(); st1.clear(); sum = 0;
    	for (int i = 1; i <= len; i++) {
    		if (a[i] >= 0) sum += a[i];
    		else insert(-a[i]);
    	}
    	ans = sum;
    	for (int i = len + 1, j = 1; i <= n; i++, j++) {
    		if (a[j] < 0) erase(-a[j]);
    		else sum -= a[j];
    		if (a[i] < 0) insert(-a[i]);
    		else sum += a[i];
    		ans = max(ans, sum);
    	}
    	return ans;
    }
    
    int main() {
    	scanf("%d%d", &n, &len);
    	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    	scanf("%d", &k);
    	LL ans = gao();
    	for (int i = 1; i <= n; i++) a[i] = -a[i];
    	ans = max(ans, gao());
    	cout << ans << endl;
    	return 0;
    }
    

     

    I:伤心的一题。。。。可以直接暴力搞,复杂度不是很高,因为毕竟约数就不超过sqrt(n)个。我还花很久撸了一个KMP。。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int maxn = 1000005;
    
    int f[maxn];
    
    inline void getfail(char *str) {
        int m = strlen(str);
        f[0] = f[1] = 0;
        for(int i = 2;i <= m;i++) {
            int j = f[i - 1];
            while(j && str[i - 1] != str[j]) j = f[j];
            if(str[i - 1] == str[j]) f[i] = j + 1;
            else f[i] = 0;
        }
    }
    
    int gao(char *str) {
    	int n;
    	n = strlen(str);
    	getfail(str);
    	if(f[n] > 0 && n % (n - f[n]) == 0) {
    		return (n - f[n]);
    	}
    	else return n;
    }
    
    char str1[maxn], str2[maxn];
    
    int main() {
        int n,kase = 0;
        while(scanf("%s%s",str1, str2) != EOF) {
    		int p1 = gao(str1), p2 = gao(str2);
    		int len1 = strlen(str1), len2 = strlen(str2);
    		if(strncmp(str1, str2, max(p1, p2)) == 0) {
    			if(p1 == p2) {
    				int ans = 0;
    				for(int i = p1; i <= min(len1, len2); i += p1) {
    					if(len1 % i == 0 && len2 % i == 0) {
    						ans++;
    					}
    				}
    				printf("%d
    ", ans);
    			}
    			else puts("1");
    		}
    		else {
    			puts("0");
    		}
    	}
    	return 0;
    }
    

    J: DP水题,题目很长。。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <bitset>
    #include <queue>
    #include <stack>
    #include <string>
    #include <iostream>
    #include <cmath>
    #include <climits>
    
    using namespace std;
    
    struct Board {
    	int a, b;
    	Board(int a = 0, int b = 0) : 
    		a(a), b(b) {}
    	bool operator == (const Board &x) const {
    		return a == x.a && b == x.b;
    	}
    	bool operator < (const Board &x) const {
    		if(x.a == a) return x.b < b;
    		return x.a < a;
    	}
    };
    
    const int mod = 1e9 + 7;
    
    vector<Board> vec;
    int f[4000][300][2], n, l;
    
    int main() {
    	scanf("%d%d", &n, &l);
    	for(int i = 1; i <= n; i++) {
    		int a, b; scanf("%d%d", &a, &b);
    		if(a > b) swap(a, b);
    		vec.push_back(Board(a, b));
    	}
    	sort(vec.begin(), vec.end());
    	//vec.erase(unique(vec.begin(), vec.end()), vec.end());
    	int cnt_board = vec.size();
    	for(int i = 1; i <= l; i++) {
    		for(int j = 0; j < cnt_board; j++) {
    			if(i == vec[j].b) {
    				f[i][j][0] = (f[i][j][0] + 1) % mod;
    			}
    			if(i == vec[j].a && vec[j].a != vec[j].b) {
    				f[i][j][1] = (f[i][j][1] + 1) % mod;
    			}
    			else for(int k = 0; k < cnt_board; k++) if(j != k) {
    				if(i - vec[j].b > 0) {
    					if(vec[j].b == vec[k].a) f[i][j][0] = (f[i - vec[j].b][k][0] + f[i][j][0]) % mod;
    					if(vec[j].b == vec[k].b) f[i][j][0] = (f[i - vec[j].b][k][1] + f[i][j][0]) % mod;
    				}
    				if(i - vec[j].a > 0 && vec[j].a != vec[j].b) {
    					if(vec[j].a == vec[k].a) f[i][j][1] = (f[i - vec[j].a][k][0] + f[i][j][1]) % mod;
    					if(vec[j].a == vec[k].b) f[i][j][1] = (f[i - vec[j].a][k][1] + f[i][j][1]) % mod;
    				}
    			}
    			//printf("for length:%d, (%d,%d) ans is %d %d
    ", i, vec[j].a, vec[j].b, f[i][j][0], f[i][j][1]);
    		}
    	}
    	int ans = 0;
    	for(int i = 0; i < cnt_board; i++) {
    		ans = (ans + f[l][i][0]) % mod;
    		ans = (ans + f[l][i][1]) % mod;
    	}
    	printf("%d
    ", ans);
    	return 0;
    }
    

    K: 原本拉这题想考DP的,没想到直接找规律就可以过。。。

    L:水题,注意相加之后不要溢出了。。

     

  • 相关阅读:
    20101029总结
    编程感悟
    编程实现>ASP.NET 3.5开发范例精讲精析>探讨SqlDataSource控件
    GET代替POST?
    php调试工具安装
    php 命令行方式使用
    多为数组转换成一维递归
    mysql优化相关
    操作目录
    递归树
  • 原文地址:https://www.cnblogs.com/rolight/p/4106521.html
Copyright © 2020-2023  润新知