首页 > 其他分享 >2022 杭电多校解题报告 第一场

2022 杭电多校解题报告 第一场

时间:2022-08-27 19:00:27浏览次数:84  
标签:杭电多校 typedef dist int long 解题 2022 include define

B. Dragon slayer(二进制枚举 + bfs)

题意:给定一个n * m的网格,视格子中间为点,格线为墙,指定x堵墙(x <= 15),穿过一堵墙耗费一体力,问从起点到终点的最小体力为多少
分析: 注意到墙的数量很小,所以可以考虑二进制枚举哪些墙被拆,然后bfs 判断可达性,这题难点在于他给的图很特殊,所以将原图扩大二倍,比较好写

ac 代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#include <random>
//#pragma GCC optimize(3)
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
using namespace std;
 
typedef unsigned long long uLL;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 50,M = 10010,INF = 0x3f3f3f3f,mod = 1e9 + 7;
const double INFF = 0x7f7f7f7f7f7f7f7f,pi = acos(-1.0);
 
int n,m,k,t;

struct Wall
{
    int x1,y1,x2,y2;
}wall[N];
PII s,e;
bool st[N][N],g[N][N];
int dx[] = {1,0,-1,0},dy[] = {0,1,0,-1};
void add(Wall & w)
{
    int x1 = w.x1,y1 = w.y1,x2 = w.x2,y2 = w.y2;
    if(x1 == x2) for(int i = min(y1,y2);i <= max(y1,y2);i ++) g[x1][i] = true;
    else for(int i = min(x1,x2);i <= max(x1,x2);i ++) g[i][y1] = true;
}

void del(Wall & w)
{
    int x1 = w.x1,y1 = w.y1,x2 = w.x2,y2 = w.y2;
    if(x1 == x2) for(int i = min(y1,y2);i <= max(y1,y2);i ++) g[x1][i] = false;
    else for(int i = min(x1,x2);i <= max(x1,x2);i ++) g[i][y1] = false;
}

bool bfs()
{
    queue<PII> q;
    memset(st,0,sizeof st);
    q.push({s.x,s.y});
    st[s.x][s.y] = true;

    while(q.size())
    {
        PII t = q.front();
        q.pop();
        if(t.x == e.x && t.y == e.y) return true;
        for(int i = 0;i < 4;i ++)
        {
            int x = t.x + dx[i],y = t.y + dy[i];
            if(x <= 0 || x >= 2 * n || y <= 0 || y >= 2 * m) continue;
            if(st[x][y] || g[x][y]) continue;
            st[x][y] = true;
            q.push({x,y});
        }
    }
    return false;
}

int main()
{
    ios;
    cin >> t;
    while(t --)
    {
        memset(g,0,sizeof g);
        cin >> n >> m >> k;
        cin >> s.x >> s.y >> e.x >> e.y;
        s.x = s.x * 2 + 1,s.y = s.y * 2 + 1;
        e.x = e.x * 2 + 1,e.y = e.y * 2 + 1;
        for(int i = 0;i < k;i ++)
        {
            int x1,y1,x2,y2;
            cin >> x1 >> y1 >> x2 >> y2;
            wall[i] = {x1 + x1,y1 + y1,x2 + x2,y2 + y2};
        }

        int ans = 0;

        for(int i = 0;i < (1 << k);i ++)
        {
            int cnt = 0;
            for(int k = 15;k >= 0;k --) if(i >> k & 1) cnt ++;
            if(cnt <= ans) continue;
            for(int k = 15;k >= 0;k --) if(i >> k & 1) add(wall[k]);
            if(bfs()) ans = cnt;
            for(int k = 15;k >= 0;k --) if(i >> k & 1) del(wall[k]);
        }

        cout << k - ans << endl;
    }
    return 0;
}

C. Backpack(dp + bitset优化)

题意 :背包问题变种,求如何在恰好塞满背包的前提下让所有背包里的物品价值总异或和最大。
分析 :设 \(f[i,j,k]\) 表示前i个物品中当前容量为j的情况下能否凑出异或和为 k 的
对于某个物品
选:\(f[i,j,k] |= f[i - 1,j - v,k \bigoplus w]\)
不选 :\(f[i,j,k] |= f[i - 1,j,k]\)
第一维可以用滚动数组优化掉,然后用bitset优化。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#include <random>
//#pragma GCC optimize(3)
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
using namespace std;
 
typedef unsigned long long uLL;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 1100,M = 10010,INF = 0x3f3f3f3f,mod = 1e9 + 7;
const double INFF = 0x7f7f7f7f7f7f7f7f,pi = acos(-1.0);
 
int n,m,k,t;
bitset<N> f[N],g[N];

void init()
{
	for(int i = 0;i <= 1024;i ++) f[i].reset(),g[i].reset();
}

int main()
{
	ios;
	cin >> t;
	while(t --)
	{
		cin >> n >> m;
		init();
		f[0][0] = 1;
		for(int i = 1;i <= n;i ++)
		{
			int w,v;
			cin >> v >> w;
			for(int j = 0;j < 1024;j ++) g[j] = f[j] << v;
			for(int j = 0;j < 1024;j ++) f[j] |= g[j ^ w];
		}

		bool success = false;
		for(int i = 1024;i >= 0;i --) 
		if(f[i][m])
		{
			cout << i << endl;
			success = true;
			break;
		}
		if(!success) cout << -1 << endl;
	}
	return 0;
}

D. Ball(枚举 + bitset)

题意 :给定棋盘上的n个点,找到三元组\((i,j,k)\) 使得i,j,k三者之间的曼哈顿距离的中位数为素数,问这样的三元组的个数
分析 :线性筛处理素数,将每两个点之间的距离预处理出来,按距离排序,从小到大枚举这些边。因为我们是从小到大枚举的这些边,那么在枚举当前边之前的边都是比较小的,我们在枚举完前面的边都做一个标记,最后找枚举过的边和没有枚举过的边即可。

ac代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#include <random>
//#pragma GCC optimize(3)
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
using namespace std;
 
typedef unsigned long long uLL;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 2010,M = 10010,INF = 0x3f3f3f3f,mod = 1e9 + 7;
const double INFF = 0x7f7f7f7f7f7f7f7f,pi = acos(-1.0);
 
int n,m,k,t;

int primes[N * N],cnt;
bool st[N * N];
bitset<N> p[N];

struct Edge
{
	int a,b,w;
	bool operator < (const Edge & t)const
	{
		return w < t.w;
	}
}edges[N * N];

void get_primes(int n)
{
	st[1] = true;
    for(int i = 2;i<=n;i++)
    {
        if(!st[i]) primes[cnt++] = i;
        for(int j = 0 ; primes[j]<=n/i;j++)
        {
            st[primes[j]*i] = true;
            if(i % primes[j] == 0) break;//此时primes[j] 为 i 的最小质因子
        }
    }
}

int main()
{
	ios;
	get_primes(200010);

	cin >> t;
	while(t --)
	{
		LL idx = 0,ans = 0;
		cin >> n >> m;
		vector<int> x(n + 1),y(n + 1);
		for(int i = 1;i <= n;i ++) cin >> x[i] >> y[i],p[i].reset();
		p[0].reset();
		for(int i = 1;i <= n;i ++)
			for(int j = i + 1;j <= n;j ++)
				edges[idx ++] = {i,j,abs(x[i] - x[j]) + abs(y[i] - y[j])};
		sort(edges,edges + idx);
		for(int i = 0;i < idx;i ++)
		{	
			int a = edges[i].a,b = edges[i].b,w = edges[i].w;
			if(!st[w]) ans += (p[a] ^ p[b]).count();
			p[a][b] = 1,p[b][a] = 1;
		}

		cout << ans << endl;

	}
	return 0;
}

H. Path(分层图最短路)

题意 :给你一个n个点m条边的无向图,m条边中有两种边,一种是特殊边,一种是普通边,经过这条特殊边后我们可以以0花费到达任意不和它相邻的点,而经过普通边我们需要花费\(w_i − K\),问从源点到各个点的最小花费是多少

分析 :这道题我们用分层图来写,以dist[i][0]表示是从特殊边到达i的最小距离,dist[i][1]表示是从普通边到达i的最小距离,然后我们从源点跑一边dijkstra,需要注意的是如果经过了一条特殊边那么我们就把其他不与该边相邻的点从队列中删除,因为这些点的距离就等于到达特殊边的距离,而因为dijkstra算法我们很容易知道这样的距离是最小的

ac代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#include <set>
#include <sstream>
#include <fstream> 
#include <cmath>
#include <iomanip>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#include <random>
//#pragma GCC optimize(3)
#define x first
#define y second
#define ios ios::sync_with_stdio(false),cin.tie(0);
#define endl '\n'
#define pb push_back
#define all(x) x.begin(),x.end()
#define all1(x) x.begin()+1,x.end()
using namespace std;
 
typedef unsigned long long uLL;
typedef long long LL;
typedef pair<int,int> PII;
 
const int N = 1000010,M = 10010,INF = 0x3f3f3f3f,mod = 1e9 + 7;
const double INFF = 0x7f7f7f7f7f7f7f7f,pi = acos(-1.0);
 
int n,m,k,t;
int h[N],e[N],ne[N],w[N],is[N],idx;
struct node
{
	int a;
	LL w;
	int is;
	bool operator < (const node & t)const
	{
		return w > t.w;
	}
};
LL dist[N][2];
bool st[N][2];
void add(int a,int b,int c,int d)
{
	e[idx] = b,w[idx] = c,is[idx] = d,ne[idx] = h[a],h[a] = idx ++;
}

void dijkstra(int s)
{
	set<int> S;
	for(int i = 1;i <= n;i ++)
	{
		if(i != s) S.insert(i);
		dist[i][0] = dist[i][1] = 1e18;
		st[i][0] = st[i][1] = 0;
	}

	 priority_queue<node> heap;
	 dist[s][0] = 0;
	 heap.push({s,0,0});
	 vector<int> vis(n + 1);
	 int cnt = 0;
	 while(heap.size())
	 {
	 	node t = heap.top();
	 	heap.pop();
	 	cnt ++;

	 	int ver = t.a,Is = t.is;
	 	if(!Is) S.erase(ver);
	 	else
	 	{
	 		for(int i = h[ver];~ i;i = ne[i])
	 		{
	 			int j = e[i];
	 			vis[j] = cnt;
	 		}

	 		vector<int> x;
	 		for(auto i : S)
	 		if(vis[i] != cnt)
	 		{
	 			x.pb(i);
	 			dist[i][0] = dist[ver][1	];
	 			heap.push({i,dist[i][0],0});
	 		}
	 		for(auto i : x) S.erase(i);
	 	}
	 	int y = 0;
	 	if(Is) y -= k;
	 	if(st[ver][Is]) continue;
	 	st[ver][Is] = true;
	 	for(int i = h[ver];~ i;i = ne[i])
	 	{
	 		int j = e[i];
	 		if(dist[j][is[i]]  > dist[ver][Is] + w[i] + y)
	 		{
	 			dist[j][is[i]] = dist[ver][Is] + w[i] + y;
	 			heap.push({j,dist[j][is[i]],is[i]});
	 		}
	 	}
	 }
}

int main()
{
	ios;
	cin >> t;
	while(t --)
	{
		int s;
		cin >> n >> m >> s >> k;
		for(int i = 1;i <= n;i ++) h[i] = -1;
		idx = 0;
		while(m --)
		{
			int a,b,c,d;
			cin >> a >> b >> c >> d;
			add(a,b,c,d);
		}
		dijkstra(s);
		for(int i = 1;i <= n;i ++)
			if(min(dist[i][0],dist[i][1]) == 1e18) cout << -1 << ' ';
			else cout << min(dist[i][0],dist[i][1]) << ' ';
		cout << endl; 


	}
	return 0;
}

标签:杭电多校,typedef,dist,int,long,解题,2022,include,define
From: https://www.cnblogs.com/notyour-young/p/16631230.html

相关文章

  • 20220827 使用EasyExcel导出复杂表格
    1、前言突然有个比较复杂的表格导出需求,写着挺好玩的,记录一下。需要实现的表格如图所示:先分析一下表格,可以看出大致分了四个区域:①第2-8行,②第9行,③第10-14行,④第15行。......
  • 适用于铁轨系统的多传感器融合SLAM(RAL 2022)
    https://mp.weixin.qq.com/s?__biz=MzIxOTczOTM4NA==&mid=2247553524&idx=2&sn=12fe2d7633ce51109976bacde02f62ec&chksm=97d4f463a0a37d75f496e3830ca2253e6cd3cfc035e611......
  • Diary -「NOI 2022」尘降
      又一次,以这样一种身份来到国赛赛场。起跑线延长出赛场外,我将于此开始又一场已知“无用”的竞技。虚无中我的尘埃盲目漂泊摇晃  时间回到数个月前的省选,\(600......
  • 2022网鼎杯网鼎杯web669wp
    大致思路:1.任意文件读取2.session伪造3.untar目录穿越,任意文件写4.yaml反序列化5.sudidd提权任意文件读取题目代码importosimportreimportyamlimporttime......
  • 2022 百度之星 初赛第一场
    题目都比较简单,OJ和评测机很坑。应该是有若干台评测机,但只有一台是正常速度,最后一题交了34发才过。A洞穴考虑每轮找到当前距离最远的一对点,他们必定都是叶子,任意选其......
  • 2022 HDU多校4
    LinkwithBracketSequenceII(区间DP)Problem有一个长度为\(n\)的括号序列,括号种类有\(m\)种,现在这个括号序列丢失了一些括号,问可能的合法括号序列个数(和)可以匹配......
  • springboot+docker发布项目20220827
    1、springboot打包项目 1)、application-dev.yml     对应配置修改 2)、项目package 生成包    3)、生成包         4)、运行......
  • 洛谷 P8496 [NOI2022] 众数 题解
    最近7年最水的D1T1。用权值线段树维护每个数出现的次数,链表维护序列。操作4即合并两棵权值线段树、两个链表,操作2就是删除链表尾的元素并在权值线段树上修改。显......
  • 一切都结束了 - NOI2022 退役记
    大概这篇文章通篇都会用全名。如果有意见可以私信联系我删除部分内容。高一的时候,很喜欢写博客。现在不那么喜欢写博客了,或许是身边有一些人可以分享了。最后一篇博客了......
  • 决定戒烟(20220826)
    以前戒烟过,不过最后又吸了。为什么会复吸?有几个原因:一是觉得吸烟的危害不大。都说吸烟有害健康,但是危害有多大不知道,我自己感觉危害不太大。二是顺其自然,不想为难自己......