ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-08-27 19:00:26  阅读:159  来源: 互联网

标签:杭电多校 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
来源: https://www.cnblogs.com/notyour-young/p/16631230.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有