Vjudge10.5

A
主席树…先放着吧

B
单源最短路+贪心。
(1)先跑一遍dij,然后再从1开始bfs,如果在最短路的边中就把它加进来,直到为k。(要注意的是dij的bfs和再次遍历的bfs是不一样的,前者的vis是看是否已经是最短路,后者的vis是看是否已经遍历过。)
(2)最短路树+贪心选边。
最短路树:定义构建一棵树,使得任意不属于根的节点x,dis(root,x)=原图走到x的最短路。
构建方法:就是在跑dijkstra时同时维护每个点是哪个点哪条边更新的,这个点这条边就是它在最短路树上的父亲/到父亲的边

dij跑一遍肯定是会得到一颗最短路树的,然后从1开始选边,每选一条边也一定会有一个点被加进来。所以贪心选边就行。(注意选满和不选满的情况)
两个方法也没差啦…

C
二分。
当前操作不定可能与之后有关+判断比查找容易:就用二分
D
数论dp,利用余数逐步推进…长见识了
其实就是从0开始一直遍历到结果为止。只存有用的数值(余数和位数和)。如果余数相同位数也相同,那之后加上一位的情况也是相同的,如果位数和已经大于s了就也不要再加位了(剪枝)
神奇=w=

#include<iostream>
#include<stdio.h>
#include<string>
#include<cstring>
#include<queue>
using namespace std;
int vis[505][5005];
int d, s;
struct node {
	int mod;
	int bit;
	string s;
};
string bfs() {
	queue<node> q;
	vis[0][0] = 1;
	node temp;
	temp.mod = 0;
	temp.bit = 0;
	temp.s = "";
	q.push(temp);
	while (!q.empty()) {
		node now, next;
		now = q.front();
		q.pop();
		//cout << now.s << "\n";
		if (now.mod == 0 && now.bit == s) {
			return now.s;
		}
		if (now.bit > s)continue;//剪枝*1
		for (int i = 0; i <= 9; i++) {
			next.mod = (now.mod * 10 + i) % d;
			next.bit = now.bit + i;
			if (!vis[next.mod][next.bit]) {//剪枝*2
				vis[next.mod][next.bit] = 1;
				next.s = now.s + (char)('0' + i);
				q.push(next);
			}
		}
	}
	return "-1";
}
int main()
{
	memset(vis, 0, sizeof(vis));
	scanf("%d%d", &d, &s);
	cout << bfs();
}

E
思维题。
要注意的是,mod操作不要太多,不然会T。

for (int i = 0; i < n; i++) {
		ans += (a[i] * b[i] * w) % mod;
		ans %= mod;
		w <<= 1;
		w %= mod;
	}

权值mod之后也不要紧,之前以为不行就每到一轮重新计算权值…就t了

(a + b) % p = (a % p + b % p) % p 
(a - b) % p = (a % p - b % p) % p 
(a * b) % p = (a % p * b % p) % p 
结合律 :((a+b) % p + c) % p = (a + (b+c) % p) % p 
	   ((a*b) % p * c)% p = (a * (b*c) % p) % p 
分配律 :((a+b)%p*c)%p = ((a*c)%p + (b*c)%p)%p 
 a ^ b % p = ((a % p)^b) % p  
重要定理
若a≡b (% p),则对于任意的c,都有(a + c)(b + c) (%p);
若a≡b (% p),则对于任意的c,都有(a * c)(b * c) (%p);
若a≡b (% p),c≡d (% p)(a + c)(b + d) (%p)(a - c)(b - d) (%p)(a * c)(b * d) (%p)(a / c)(b / d) (%p)

F
控制向左走和向右走的步数,不控制向上与向下的步数
我一开始想的是dfs搜索,但是这样要考虑很多情况,看了别人都才知道可以先预处理最短路然后判断…

思路:要是能得到向左走的步数的最小值,那么向右的步数(j-c+dis[i][j])也可以得到。
要得到就bfs最短路。
PS:因为是0-1路所以可以用deque来维护(就是优先队列啦,只不过01就两个值所以easy)

算法正确性明显可得…但是我就是想不到Q-Q哎

#include<iostream>
#include<stdio.h>
#include<cstring>
#include<queue>
using namespace std;
int n, m, r, c, x, y;
char map[2005][2005];
int dis[2005][2005];
int dir[4][2] = { 0,-1,0,1,1,0,-1,0 };
struct node {
	int x, y;
};
void bfs(int x, int y) {
	memset(dis, 1, sizeof(dis));
	deque<node> q;
	node now, next;
	dis[x][y] = 0;
	now.x = x;
	now.y = y;
	q.push_front(now);
	while (!q.empty()) {
		now = q.front();
		q.pop_front();
		for (int i = 0; i < 4; i++) {//0 right
			int tx = now.x + dir[i][0];
			int ty = now.y + dir[i][1];
			if (tx > 0 && tx <= n && ty > 0 && ty <= m && map[tx][ty] == '.') {//只用看一个变量,就是向左走的值,所以其他方向不改变值
				if (dis[tx][ty] > dis[now.x][now.y] + (i == 0)) {
					dis[tx][ty] = dis[now.x][now.y] + (i == 0);
					next.x = tx;
					next.y = ty;
					if (i == 0)q.push_back(next);
					else q.push_front(next);
				}
			}
		}
	}
}
				
int main()
{
	freopen("in.txt", "r", stdin);
	scanf("%d%d%d%d%d%d", &n, &m, &r, &c, &x, &y);
	for (int i = 1; i <= n; i++) {
		getchar();
		for (int j = 1; j <= m; j++) {
			scanf("%c", &map[i][j]);
		}
	}
	bfs(r, c);
	int cnt = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (map[i][j] == '*')continue;
				if (dis[i][j] <= x && dis[i][j]+j-c <= y) {
					cnt++;
				}
				
			}
		}
	printf("%d\n", cnt);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值