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

    咕了好几天的题解,今天总算补上了。

    T1 fish

    题意描述

    河边有⼀块鱼塘,鱼塘中有 (n) 条鱼,鱼塘边有 (m) 个摸鱼⼈。我们对这个鱼塘建⽴坐标系,已知所有鱼的坐标 ((x_1,y_1),(x_2,y_2)...(x_n,y_n)) 和所有摸鱼⼈的坐标 (a_1,a_2..a_n)(a_i) 代表第 (i) 个摸鱼⼈在坐标系中的 ((a_i, 0)) 这⼀点上)。摸鱼⼈只能摸到与他的距离不超过 (l) 的范围内的鱼。 请求出每个摸鱼⼈能摸到的鱼的数量。 注意的是,在这⾥距离定义为曼哈顿距离,即⼀条鱼 $(x, y) $和⼀个摸鱼⼈ ((a, 0)) 的距离为 (d = ∣a − x∣ + y) 。 鱼的坐标可以重叠,即⼀个点上可能存在多条鱼。问你每个摸鱼人能摸到的鱼的数量。

    (n,mleq 2 imes 10^5,1leq x_i,y_i,a_i,lleq 10^9)

    solution

    考试的时候极值设小了,挂了 (50) 分,直接倒数了。

    鱼会被摸鱼人抓到 要满足, (∣a − x∣ + yleq l) 其中 (d,y) 都是确定的,把这两项移到左边变成。

    (|a-x| leq l-y) ,然后你会发现 合法的 (x) 对应的是一段区间, ([a-(l-y),a+(l-y)])

    可以先对摸鱼人按 (x_i) 排一下序,二分出左右端点在差分一下就行。

    复杂度 (O(nlogn))

    Code(写的难看了点)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define int long long
    const int N = 2e5+10;
    const int inf = 1e13;
    int n,m,maxl,d[N],ans[N],pos[N];
    struct fish
    {
    	int x,y;
    }e[N];
    struct people
    {
    	int x,id;
    }q[N];
    inline 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 * 10 + ch - '0'; ch = getchar();}
    	return s * w;
    }
    bool comp(people a,people b)
    {
    	return a.x < b.x;
    }
    int find_L(int val)
    {
    	int L = 0, R = m+1, res = 0;
    	while(L <= R)
    	{
    		int mid = (L + R)>>1;
    		if(q[mid].x <= val)
    		{
    			res = mid;
    			L = mid + 1;
    		}
    		else R = mid - 1;
    	}
    	return res;
    }
    int find_R(int val)
    {
    	int L = 0, R = m+1, res = 0;
    	while(L <= R)
    	{ 
    		int mid = (L + R)>>1;
    		if(q[mid].x >= val)
    		{
    			res = mid;
    			R = mid - 1;
    		}
    		else L = mid + 1;
    	}
    	return res;
    }
    signed main()
    {
    	freopen("fish.in","r",stdin);
    	freopen("fish.out","w",stdout);
    	n = read(); m = read(); maxl = read();
    	for(int i = 1; i <= n; i++) 
    	{
    		e[i].x = read();
    		e[i].y = read();
    	}
    	for(int i = 1; i <= m; i++)
    	{
    		q[i].x = read();
    		q[i].id = i;
    	}
    	sort(q+1,q+m+1,comp); q[0].x = -inf; q[m+1].x = inf;
    	for(int i = 1; i <= m; i++) pos[q[i].id] = i;
    	for(int i = 1; i <= n; i++)
    	{
    		if(e[i].y > maxl) continue;
    		int l = find_L(e[i].x - (maxl - e[i].y)-1);
    		int r = find_R(e[i].x + (maxl - e[i].y)+1);
    		d[l+1]++; d[r]--;
    	}
    	for(int i = 1; i <= m; i++) d[i] = d[i-1] + d[i];
    	for(int i = 1; i <= m; i++) ans[q[i].id] = d[i];
    	for(int i = 1; i <= m; i++) printf("%lld
    ",ans[i]);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
    

    T2 package

    题⽬描述 :

    ⼜是⼀年双⼗⼀,华科的每个快递点都炸了仓库,排队领快递的场景⼗分壮观。现在⼀群学⽣开展了⼀ 项代领快递的业务,他们骑着电动⾃⾏车帮同学们领取他们的快递。 ⼀共有 (T) 件快递需要领取,每件快递都有两个属性重量 (W_i) 和⼤⼩ (S_i) 。⽽他们的电动车也分为两 类:功率不太⾼的和不太⼤的。对于每台功率不太⾼的电动车,只能装重量严格⼩于 (X_i) 的快递,但对快递的⼤⼩不做限制;对于每台不太⼤的电动车,只能装⼤⼩严格⼩于 (Y_i) 的快递,但对快递的重量不 做限制。每取 (1) 件快递需要消耗 (1) 分钟的时间,所有电单车可以同时取快递。 已知他们⼀共有 (A) 台功率不太⾼的电动车和 (B) 台不太⼤的电动车,请求出领取完所有快递所需的最短 时间(如果⽆法领取完所有的快递,输出 -1 )。

    (Tleq 10^6,a,bleq 50000, x_i,y_i,W_i,S_ileq 2 imes 10^9)

    solution

    比较神仙的贪心题。

    最后的答案与装的最多的电动车的快递数有关。显然答案有单调性。考虑二分答案 (t).

    接下来考虑如何验证。

    对于每个功率不太高的电动车,对大小没有限制,所以我们要让他在他能装的范围里面选大小比较大的装。

    先对每个 (x_i) 按从小到大排序,每个快递按 (w) 为第一关键字, (s) 为第二关键字排序。

    显然随着 (x_i) 的递增, 可选择的快递也是扩大的,把每个快递按 (s) 为关键字放入堆中,取前 (t) 大的放。。

    对于不能放的快递,则用不太大的电车来放。先对每个 (y_i) 按从大到小排一遍序。

    如果当前堆顶比 (y_i) 要大,说明当前堆顶的快递已经放不下了,直接 (return 0) .

    最后如果堆不为空,则表示当前的快递没有装完,也是 (return 0)

    复杂度 (O(nlog^2n))

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N = 1e6+10;
    int n,m,T,ans;
    int x[50010],y[50010];
    struct node
    {
    	int s,w;
    }e[N];
    inline 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 * 10 + ch - '0'; ch = getchar();}
    	return s * w;
    }
    bool comp(node a,node b)
    {
    	if(a.w == b.w) return a.s < b.s;
    	return a.w < b.w;
    }
    bool judge(int mid)
    {
    	priority_queue<int> q;
    	int now = 1;
    	for(int i = 1; i <= n; i++)
    	{
    		while(now <= T && e[now].w < x[i]) //把能选的放进堆里面
    		{
    			q.push(e[now].s);
    			now++;
    		}
    		for(int j = 1; j <= mid && !q.empty(); j++) q.pop();//选前t的取,同时pop出来表示这个快递已经被选了
    	}
    	while(now <= T)//把剩下的放进去
    	{
    		q.push(e[now].s);
    		now++;
    	}
    	for(int i = m; i >= 1; i--)
    	{
    		if(!q.empty() && q.top() >= y[i]) return 0;
    		for(int j = 1; j <= mid && !q.empty(); j++) q.pop();
    	}
    	if(q.empty()) return 1;
    	return 0;
    }
    int main()
    {
    	freopen("package.in","r",stdin);
    	freopen("package.out","w",stdout);
    	n = read(); m = read(); T = read();
    	for(int i = 1; i <= n; i++) x[i] = read();
    	for(int i = 1; i <= m; i++) y[i] = read();
    	sort(x+1,x+n+1); sort(y+1,y+m+1);
    	for(int i = 1; i <= T; i++)
    	{
    		e[i].w = read();
    		e[i].s = read();
    	}
    	sort(e+1,e+T+1,comp);
    	int L = 1, R = T;
    	while(L <= R)
    	{
    		int mid = (L + R)>>1;
    		if(judge(mid))
    		{
    			ans = mid;
    			R = mid - 1;
    		}
    		else L = mid + 1;
    	}
    	if(ans == 0) printf("%d
    ",-1);
    	else printf("%d
    ",ans);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    

    T3 arrange

    题意描述

    给你一个长度为 (n) 的 序列 (a_i) ,对于 ({A_n}) 的一个排列 (f_n) 如果 (displaystylesum_{i=2}^{n} |f_i-f_{i-1}|leq L) ,则称他是符合要求的。求满足条件的排列个数。 (nleq 100,a_ileq 1000)

    solution

    神仙 (dp) 题,不会。

    正解,咕咕咕。。。

    T4 game

    题意描述

     最近,小P迷上了一款叫做2048的游戏。这块游戏在一个 (n imes n) 的棋盘中进行,棋盘的每个格子中可能有一个形如 (2^k(k∈N∗))的数,也可能是空的。游戏规则介绍如下:
      1.游戏开始时棋盘内将会生成两个数字,生成的数字仅可能为2或4;
      2.每次操作,玩家可以选择上、下、左、右四个方向进行平移;
      3.以向上平移为例,从上往下考虑每个不为空的格子,若上方与之相邻的格子为空,则将该格子上的数字移动至相邻格子。在一次位移中,每个数字会进行多次移动直到不能移动为止。
      4.以向上平移为例,从上往下考虑每个不为空的格子,若上方与之相邻的数字恰好与其相等,则两个数字可以合并,新生成的数字为原来两个数之和。在一次合并中,每个数字只能与其它数合并一次,可以同时合并多对数字,但不能连续合并;
      5.每次操作由位移+合并+位移组成,若操作后棋盘局面发生变化,则该操作为有效操作,其有效得分为合并过程中所有新生成的数字之和;
      6.在每次操作后,棋盘内都会新生成一个数字2或4,数字只会在空格子处生成;
      7.当棋盘被数字填满,玩家无法进行任何有效操作时,游戏结束,游戏总得分为所有操作的有效得分之和。

    img

     

     为了降低难度,小P对2048游戏进行了一些改动。在游戏开始前,小P会告诉你棋盘的初始状态,并给你若干次操作。每次操作由方向变量、位置参数和一个数字组成,方向变量代表你在本次操作中的移动方向,给定的数字为本次操作之后将会生成的数字的大小,而位置参数将决定生成数字的位置。若位置参数为K操作后棋盘中空格子的数量为 (r),则生成数字的位置从上到下从左到右((1+K mod r))个空格子。如果每次操作为无效操作,则游戏结束,而当所有操作都完成后,游戏同样结束。(注意:改动后,游戏结束时棋盘不一定被数字填满。

    img

      现在小P问你,在游戏结束前你一共进行了多少次有效操作,最后你的游戏总得分是多少

    solution

    恶心人的大模拟,没什么好说的,就是要注意各种细节。

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define int long long
    int n,m,cnt,ans,x,y,w,di,ki,vi,flag;
    int e[20][20];
    struct node
    {
    	int x,y;
    }q[10010];
    inline 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 * 10 + ch - '0'; ch = getchar();}
    	return s * w;
    }
    bool comp(node a,node b)
    {
    	if(a.x == b.x) return a.y < b.y;
    	return a.x < b.x;
    }
    bool gameover()
    {
    	for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(!e[i][j]) return 0;
    	for(int i = 1; i < n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			if(e[i][j] == e[i+1][j]) return 0;
    		}
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j < n; j++)
    		{
    			if(e[i][j] == e[i][j+1]) return 0;
    		}
    	}
    	return 1;
    }
    void up()
    {
    	for(int j = 1; j <= n; j++)
    	{
    		for(int i = 1; i <= n; i++)
    		{
    			int tmp = e[i][j], r = i;
    			if(tmp == 0) continue;
    			while(r-1 >= 1 && !e[r-1][j]) r--;
    			if(r != i) flag = 1;
    			e[i][j] = 0; e[r][j] = tmp;
    		}
    	}
    	for(int j = 1; j <= n; j++)
    	{
    		for(int i = 1; i <= n; i++)
    		{
    			if(e[i][j] == e[i-1][j] && e[i][j] != 0)
    			{
    				flag = 1;
    				e[i-1][j] *= 2;
    				e[i][j] = 0;
    				ans += e[i-1][j];
    			}
    		}
    	}
    	for(int j = 1; j <= n; j++)
    	{
    		for(int i = 1; i <= n; i++)
    		{
    			int tmp = e[i][j], r = i;
    			if(tmp == 0) continue;
    			while(r-1 >= 1 && !e[r-1][j]) r--;
    			if(r != i) flag = 1;
    			e[i][j] = 0; e[r][j] = tmp;
    		}
    	}
    }
    void down()
    {
    	for(int j = 1; j <= n; j++)
    	{
    		for(int i = n; i >= 1; i--)
    		{
    			int tmp = e[i][j], r = i;
    			if(tmp == 0) continue;
    			while(r+1 <= n && !e[r+1][j]) r++;
    			if(r != i) flag = 1;
    			e[i][j] = 0; e[r][j] = tmp;
    		}
    	}
    	for(int j = 1; j <= n; j++)
    	{
    		for(int i = n; i >= 1; i--)
    		{
    			if(e[i][j] == e[i+1][j] && e[i][j] != 0)
    			{
    				flag = 1;
    				e[i+1][j] *= 2;
    				e[i][j] = 0;
    				ans += e[i+1][j];
    			}
    		}
    	}
    	for(int j = 1; j <= n; j++)
    	{
    		for(int i = n; i >= 1; i--)
    		{
    			int tmp = e[i][j], r = i;
    			if(tmp == 0) continue;
    			while(r+1 <= n && !e[r+1][j]) r++;
    			if(r != i) flag = 1;
    			e[i][j] = 0; e[r][j] = tmp;
    		}
    	}
    }
    void left()
    {
    //	cout<<res<<"rejp"<<endl;
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			int tmp = e[i][j], r = j;
    			if(tmp == 0) continue;
    			while(r-1 >= 1 && !e[i][r-1]) r--;
    			if(r != j) flag = 1;
    			e[i][j] = 0; e[i][r] = tmp;
    		}
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			if(e[i][j] == e[i][j-1] && e[i][j] != 0)
    			{
    				flag = 1;
    				e[i][j-1] *= 2;
    				e[i][j] = 0;
    				ans += e[i][j-1];
    			}
    		}
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			int tmp = e[i][j], r = j;
    			if(tmp == 0) continue;
    			while(r-1 >= 1 && !e[i][r-1]) r--;
    			if(r != j) flag = 1;
    			e[i][j] = 0; e[i][r] = tmp; 
    		}
    	}
    }
    void right()
    {
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = n; j >= 1; j--)
    		{
    			int tmp = e[i][j], r = j;
    			if(tmp == 0) continue;
    			while(r+1 <= n && !e[i][r+1]) r++;
    			if(r != j) flag = 1;
    			e[i][j] = 0; e[i][r] = tmp;
    		}
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = n; j >= 1; j--)
    		{
    			if(e[i][j] == e[i][j+1] && e[i][j] != 0)
    			{
    				flag = 1;
    				e[i][j+1] *= 2;
    				e[i][j] = 0;
    				ans += e[i][j+1];
    			}
    		}
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = n; j >= 1; j--)
    		{
    			int tmp = e[i][j], r = j;
    			if(tmp == 0) continue;
    			while(r+1 <= n && !e[i][r+1]) r++;
    			if(r != j) flag = 1;
    			e[i][j] = 0; e[i][r] = tmp; 
    		}
    	}
    }
    void remove(int ki,int vi)
    {
    	int num = 0;
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= n; j++)
    		{
    			if(!e[i][j])
    			{
    				q[++num].x = i;
    				q[num].y = j;
    			}
    		}
    	}
    	sort(q+1,q+num+1,comp);
    	if(num == 0) return;
    	int tmp = (ki % num) + 1;
    	e[q[tmp].x][q[tmp].y] = vi;
    }
    signed main()
    {
    	freopen("game.in","r",stdin);
    	freopen("game.out","w",stdout);
    	n = read(); m = read();
    	x = read(); y = read(); w = read(); e[x][y] = w;
    	x = read(); y = read(); w = read(); e[x][y] = w;
    	for(int i = 1; i <= m; i++)
    	{
    		di = read(); ki = read(); vi = read(); flag = 0;
    		if(gameover()) 
    		{
    			cnt = i-1;
    			printf("%lld
    %lld
    ",cnt,ans);
    			return 0;
    		}
    		if(di == 0) up();
    		if(di == 1) down();
    		if(di == 2) left();
    		if(di == 3) right();
    		remove(ki,vi);
    		if(flag == 0)
    		{
    			cnt = i-1;
    			printf("%lld
    %lld
    ",cnt,ans);
    			return 0;
    		}
    	}
    	cnt = m;
    	printf("%lld
    ",cnt);
    	printf("%lld
    ",ans);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    xps坐标计算
    xps文档
    xps坐标提取
    javascript
    python 类的继承
    PHP parse_url函数示例
    PHP 二维数组按照指定键排序(正序或倒叙均可)
    PHP substr()函数参数解释 通俗易懂
    PHP四大经典排序算法源码
    X友 NC 远程命令执行
  • 原文地址:https://www.cnblogs.com/genshy/p/14034313.html
Copyright © 2011-2022 走看看