2019年陕西省大学生程序设计竞赛 补题记录

B - Grid with Arrows(简单图论)

  • 把二维平面转化成一维的点,每个位置的箭头和数字表示一条有向边
  • 从入度为 0 的地方开始 dfs,再判断是不是所有点都遍历过了
  • 如果没有入度为 0 的点,说明所有点都在环上,但是不一定都在同一个环上,所以随便选一个点dfs一下,看看能不能经过所有点
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e6 + 10;
const int maxn = 1e6;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m; cin >> n >> m;
	vector<string> way(n + 1);
	vector<int> g(n * m + 10);
	for (int i = 1; i <= n; i ++ )
	{
		cin >> way[i];
		way[i] = " " + way[i];
	}
	auto getver = [&](int x, int y)
	{
		return (x - 1) * m + y;
	};
	vector<int> ind(n * m + 10);
	for (int i = 1; i <= n; i ++ )
	{
		for (int j = 1; j <= m; j ++ )
		{
			int x; cin >> x;
			int ver = getver(i, j);
			int nv = 0;
			if (way[i][j] == 'u' && i - x > 0) nv = getver(i - x, j);
			else if (way[i][j] == 'd' && i + x <= n) nv = getver(i + x, j);
			else if (way[i][j] == 'l' && j - x > 0) nv = getver(i, j - x);
			else if (way[i][j] == 'r' && j + x <= m)  nv = getver(i, j + x);
			g[ver] = nv;
			if (nv != 0) ind[nv] ++ ;
		}
	}
	bool flag = false;
	vector<bool> st(n * m + 1);
	function<void(int)> dfs = [&](int u)
	{
		int nxt = g[u];
		if (st[nxt] || nxt == 0) return;
		st[nxt] = true;
		dfs(nxt);
	};
	for (int i = 1; i <= n * m; i ++ )
	{
		if (ind[i] == 0)
		{
			flag = true;
			st[i] = true;
			dfs(i);
			break;
		}
	}
	if (flag) // 已经dfs过一次
	{
		for (int i = 1; i <= n * m; i ++ ) // 检查是否还有点没遍历到
		{
			if (!st[i])
			{
				cout << "No\n";
				return;
			}
		}
		cout << "Yes\n";
	}
	else // 点都在环上
	{
		st[1] = true;
		dfs(1);
		for (int i = 1; i <= n * m; i ++ ) // 检查是否还有点没遍历到
		{
			if (!st[i])
			{
				cout << "No\n";
				return;
			}
		}
		cout << "Yes\n";
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

C - 0689(思维 + 后缀统计)

  • 从前往后枚举每个地方为起点,终点只需要看它之后有多少个数作为终点,rotate 一下和起点不一样:
    • 0 0 0 为起点,终点可以是 6 6 6 , 8 8 8 , 9 9 9
    • 6 6 6 为起点,终点可以是 0 0 0 , 6 6 6 , 8 8 8
    • 8 8 8 为起点,终点可以是 0 0 0 , 6 6 6 , 9 9 9
    • 9 9 9 为起点,终点可以是 0 0 0 , 8 8 8 , 9 9 9
  • 为什么可以这么计算呢,因为如果开头结尾 rotate 一下是一样的,那就可以直接选择更短的区间进行 rotate 达到一样的效果
  • 所以统计一下后缀,也就是每个数后面有多少个 0689,计算一下就行了
  • 坑点是需不需要加自身呢?如果有 0 或者 8 的话,rotate 一下就是本身,所以需要加自身,另一种需要加自身的情况是同时出现了 6 和 9,因为这两个数相互 rotate 相等
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e6 + 10;
const int maxn = 1e6;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	string s; cin >> s;
	int n = s.size();
	s = " " + s;
	vector<vector<int>> cnt(n + 2, vector<int>(4));
	int ans = 0;
	bool flag = false, f1 = false, f2 = false;
	for (int i = n; i >= 1; i -- )
	{
		for (int j = 0; j < 4; j ++ )
		{
			cnt[i][j] = cnt[i + 1][j];
		}
		if (s[i] == '0')
		{
			flag = true;
			cnt[i][0] ++ ;
			ans += cnt[i][1] + cnt[i][2] + cnt[i][3];
		}
		else if (s[i] == '6')
		{
			f1 = true;
			cnt[i][1] ++ ;
			ans += cnt[i][0] + cnt[i][1] + cnt[i][2];
		}
		else if (s[i] == '8')
		{
			flag = true;
			cnt[i][2] ++ ;
			ans += cnt[i][0] + cnt[i][1] + cnt[i][3];
		}
		else if (s[i] == '9')
		{
			f2 = true;
			cnt[i][3] ++ ;
			ans += cnt[i][0] + cnt[i][2] + cnt[i][3];
		}
	}
	if (f1 && f2) flag = true;
	if (flag) cout << ans + 1 << '\n';
	else cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

D - Pick Up(思维)

  • 答案初始化为baobao直接去商场的时间
  • x a ,   y a ,   x b ,   y b x_a,\ y_a, \ x_b,\ y_b xa, ya, xb, yb 形成的矩形中,找出距离商场最近的点 d d d,两个人先走到 d d d 再去商场和直接去商场的路径是一样的
  • 如果baobao先到 d d d,那DreamGrid可以在去商场的路上带上baobao,所以答案和DreamGrid去商场的时间取最小值
  • 如果DreamGrid先到 d d d,那他会先去接baobao,从出发到接到baobao的时间可以计算出来,另外加上一起去商场的时间就可以了
  • 坑点是卡cin
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

double cal(int x1, int y1, int x2, int y2, double v)
{
	return 1.0 * (labs(x1 - x2) + labs(y1 - y2)) / v;
}

void solve()
{
	double a, b;
	int xa, ya, xb, yb, xc, yc;
	scanf("%Lf%Lf%lld%lld%lld%lld%lld%lld", &a, &b, &xa, &ya, &xb, &yb, &xc, &yc);
	double ans = cal(xa, ya, xc, yc, a); // baobao到商场
	int l = min(xa, xb), r = max(xa, xb);
	int u = min(ya, yb), d = max(ya, yb);
	int xd = max(l, min(r, xc)), yd = max(u, min(d, yc));
	double ta = cal(xa, ya, xd, yd, a), tb = cal(xb, yb, xd, yd, b);
	if (ta < tb) ans = min(ans, cal(xb, yb, xc, yc, b));
	else
	{
		double t = cal(xa, ya, xb, yb, a + b);
		double dis = labs(xa - xc) + labs(ya - yc) - t * a;
		ans = min(ans, t + dis / b);
	}
	printf("%.8Lf\n", ans);
}

signed main()
{
	// ios::sync_with_stdio(false);
	// cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

E - Turn It Off(二分)

  • 直接二分,不要再无脑贪心了
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e6 + 10;
const int maxn = 1e6;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, k;
	cin >> n >> k;
	string s; cin >> s;
	int l = 1, r = n;
	auto check = [&](int mid)
	{
		int cnt = 0;
		for (int i = 0; i < s.size(); i ++ )
		{
			if (s[i] == '0') continue;
			cnt ++ ;
			i += mid - 1;
		}
		if (cnt > k) return false;
		else return true;
	};
	while (l < r)
	{
		int mid = l + r >> 1;
		if (check(mid)) r = mid;
		else l = mid + 1;
	}
	cout << r << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

F - K-hour Clock(思维)

  • x + y < z x+y<z x+y<z ,不可能实现
  • x + y = z x+y=z x+y=z ,输出比 z z z 大的任何一个数
  • x + y > z x+y>z x+y>z,肯定是先从 x x x k k k,再从 0 0 0 z z z,所以我们先把后面多的 z z z 减掉,再把前面少的 x x x 加上,这样得到的数一定是 k k k 的倍数,判断一下这个数是不是都大于 x x x y y y,是的话直接输出就好了
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e6 + 10;
const int maxn = 1e6;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int x, y, z; cin >> x >> y >> z;
	if (x + y < z)
	{
		cout << -1 << '\n';
		return;
	}
	if (x + y == z)
	{
		cout << z + 1 << '\n';
		return;
	}
	int tmp = y - z + x;
	int maxx = max(x, z);
	if (tmp > maxx) cout << tmp << '\n';
	else cout << -1 << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

H - To the Park(构造)

  • 首先 1 1 1 一定不行,然后从大到小枚举质数,如果质数的两倍大于 n n n 肯定不行
  • 把质数的倍数存起来,如果在 n n n 以内的有偶数个,正好两两配对,如果奇数个,就单独把两倍的质数提出来,之后和其余没用上的偶数配对
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

bool isprime[MAXN]; // isprime[i]表示i是不是素数
vector<int> prime;
int n; // 上限,即筛出<=n的素数
int cnt; // 已经筛出的素数个数

void euler()
{
    memset(isprime, true, sizeof(isprime)); // 先全部标记为素数
    isprime[1] = false; // 1不是素数
	prime.push_back(0);
    for(int i = 2; i <= 1e5; ++i) // i从2循环到n(外层循环)
    {
        if(isprime[i])
		{
			prime.push_back(i);
			cnt ++ ;
		}
        // 如果i没有被前面的数筛掉,则i是素数
        for(int j = 1; j <= cnt && i * prime[j] <= 1e5; ++j)
        // 筛掉i的素数倍,即i的prime[j]倍
        // j循环枚举现在已经筛出的素数(内层循环)
        {
            isprime[i * prime[j]] = false;
            // 倍数标记为合数,也就是i用prime[j]把i * prime[j]筛掉了
            if(i % prime[j] == 0) break;
            // 最神奇的一句话,如果i整除prime[j],退出循环
            // 这样可以保证线性的时间复杂度
        }
    }
}

void solve()
{
	int n; cin >> n;
	vector<bool> st(n + 1); // 哪些数已经被用过了
	vector<int> noused;
	vector<PII> ans;
	for (int i = cnt; i > 1; i -- )
	{
		int num = prime[i];
		if (num * 2 > n) continue;
		vector<int> tmp;
		int idx = 2;
		tmp.push_back(num);
		while (num * idx <= n)
		{
			if (!st[num * idx])
			{
				st[num * idx] = true;
				tmp.push_back(num * idx);
			}
			idx ++ ;
		}
		if (tmp.size() & 1)
		{
			noused.push_back(2 * num);
			ans.push_back({tmp[0], tmp[2]});
			for (int i = 3; i < tmp.size(); i += 2 ) ans.push_back({tmp[i], tmp[i + 1]});
		}
		else
		{
			for (int i = 0; i < tmp.size(); i += 2) ans.push_back({tmp[i], tmp[i + 1]});
		}
	}
	for (int i = 2; i <= n; i += 2) if (!st[i]) noused.push_back(i); 
	for (int i = 0; i < (int)(noused.size()) - 1; i += 2) ans.push_back({noused[i], noused[i + 1]});
	cout << ans.size() << ' ';
	for (auto t : ans) cout << t.first << ' ' << t.second << ' ';
	cout << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	euler();
	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

I - Unrooted Trie(dfs序 + 差分)

  • 有两种情况,这棵树就一定不是合法的字典树:

    • 一个结点连接了大于 2 个相同的字母
    • 一个结点连接了大于 1 种出现两次的字母
  • 如果不处于以上两种情况,我们只需要看那些地方不能当做根,做个标记,没做标记的地方统计答案

  • 如果一个结点连接的所有字母都只出现了一次,那对答案没有影响,如果有一个字母出现了两次,根结点必然在这两个点所在的子树里,对整个子树打标记,想到可以用 dfs 序

  • 先随便选个点开始 dfs 一下求出 dfs 序,然后遍历所有点,遍历到的点记为 u u u,相邻的字母相同的点记作 v 1 v_1 v1 v 2 v_2 v2

    • 如果 d f n [ u ] < d f n [ v 1 ] dfn[u]<dfn[v_1] dfn[u]<dfn[v1] d f n [ u ] < d f n [ v 2 ] dfn[u]<dfn[v_2] dfn[u]<dfn[v2],说明 u u u v 1 v_1 v1 v 2 v_2 v2 的父结点,那除了两个子树的其余部分都不能作为根结点,就先把全体打上+1标记,两个子树打上-1标记
    • 否则, d f n [ u ] dfn[u] dfn[u] 一定处于 d f n [ v 1 ] dfn[v_1] dfn[v1] d f n [ v 2 ] dfn[v_2] dfn[v2] 之间,不能作为根结点的部分就是 u u u 的子树除去 v 1 v_1 v1 或者 v 2 v_2 v2 的子树部分
  • 差分打标记就行

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n; cin >> n;
	vector<vector<PII>> g(n + 1);
	for (int i = 0; i < n - 1; i ++ )
	{
		int u, v;
		char c;
		cin >> u >> v >> c;
		g[u].push_back({v, c - 'a'});
		g[v].push_back({u, c - 'a'});
	}
	int timestamp = 0;
	vector<int> dfn1(n + 1), dfn2(n + 1);
	function<void(int, int)> dfs = [&](int u, int fa)
	{
		dfn1[u] = ++ timestamp;
		for (int i = 0; i < g[u].size(); i ++ )
		{
			int j = g[u][i].first, c = g[u][i].second;
			if (j == fa) continue;
			dfs(j, u);
		}
		dfn2[u] = timestamp;
	};
	dfs(1, -1);
	vector<int> diff(n + 2);
	for (int i = 1; i <= n; i ++ )
	{
		vector<vector<int>> cnt(26);
		int flag = -1;
		for (int j = 0; j < g[i].size(); j ++ )
		{
			int v = g[i][j].first, c = g[i][j].second;
			cnt[c].push_back(v);
			if (cnt[c].size() > 2)
			{
				cout << 0 << '\n';
				return;
			}
			else if (cnt[c].size() == 2)
			{
				if (flag != -1)
				{
					cout << 0 << '\n';
					return;
				}
				else flag = c;
			}
		}

		if (flag == -1) continue;

		int v1 = cnt[flag][0], v2 = cnt[flag][1];
		if (dfn1[v1] > dfn1[v2]) swap(v1, v2);
		if (dfn1[i] < dfn1[v1] && dfn1[i] < dfn1[v2])
		{
			diff[1] ++ , diff[n + 1] ++ ;
			diff[dfn1[v1]] -- , diff[dfn2[v1] + 1] ++ ;
			diff[dfn1[v2]] -- , diff[dfn2[v2] + 1] ++ ;
		}
		else
		{
			diff[dfn1[i]] ++ , diff[dfn2[i] + 1] -- ;
			diff[dfn1[v2]] -- , diff[dfn2[v2] + 1] ++ ;
		}
	}

	int ans = 0;
	for (int i = 1; i <= n; i ++ )
	{
		diff[i] += diff[i - 1];
		if (diff[i] == 0) ans ++ ;
	}
	cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

J - Coolbits(位运算)

  • 按位考虑答案应该是很常见的思路了
  • 从高位往低位考虑,假设当前在考虑第 i i i 位,用 r e s [ j ] res[j] res[j] 表示第 j j j 个区间从最高位到第 i + 1 i+1 i+1 位选的数:
    • i i i 位为 1 1 1,条件是对于所有的 j j j [ r e s j + 2 i ,   r e s j + 2 i + 1 − 1 ] [res_j+2^i,\ res_j+2^{i+1}-1] [resj+2i, resj+2i+11] 必须与 [ l j ,   r j ] [l_j,\ r_j] [lj, rj] 有交集,对于第 j j j 个数,让 r e s [ j ] res[j] res[j] 加上 2 i 2^i 2i 即可
    • 否则第 i i i 位为 0 0 0
      • 如果 [ r e s j + 2 i ,   r e s j + 2 i + 1 − 1 ] [res_j+2^i,\ res_j+2^{i+1}-1] [resj+2i, resj+2i+11] [ l j ,   r j ] [l_j,\ r_j] [lj, rj] 没有交集,第 j j j 个数的第 i i i 位取 0 0 0 r e s [ j ] res[j] res[j] 不做改变
      • 如果有交集,就看一下 r e s j + 2 i − 1 res_j+2^i-1 resj+2i1 在不在 [ l j ,   r j ] [l_j,\ r_j] [lj, rj],如果在的话,直接第 i i i 位填 0 0 0,后面全填 1 1 1 就可以了(第 j j j 个数之后都不需要再考虑了),如果不在这一位就只能填 1 1 1
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n; cin >> n;
	vector<PII> a(n + 1);
	vector<int> res(n + 1);
	vector<bool> st(n + 1);
	for (int i = 1; i <= n; i ++ ) cin >> a[i].first >> a[i].second;
	int ans = 0;
	for (int i = 31; i >= 0; i -- ) // 目前考虑到哪一位了
	{
		bool flag = true; // 当前位能不能填1
		for (int j = 1; j <= n; j ++ )
		{
			if (st[j]) continue;
			int tmpl = res[j] + (1ll << i), tmpr = res[j] + (1ll << (i + 1)) - 1;
			int l = a[j].first, r = a[j].second;
			if (r < tmpl || l > tmpr)
			{
				flag = false;
				break;
			}
		}
		if (flag) // 当前位取1
		{
			for (int j = 1; j <= n; j ++ )
			{
				if (st[j]) continue;
				res[j] += (1 << i);
			}
			ans += (1ll << i);
		}
		else // 当前位取0
		{
			for (int j = 1; j <= n; j ++ )
			{
				if (st[j]) continue;
				int tmpl = res[j] + (1ll << i), tmpr = res[j] + (1ll << (i + 1)) - 1;
				int l = a[j].first, r = a[j].second;
				if (r >= tmpl && l <= tmpr)
				{
					int tmp = res[j] + (1ll << i) - 1;
					if (tmp >= l && tmp <= r)
					{
						res[j] += (1ll << i) - 1;
						st[j] = true;
					}
					else res[j] += (1ll << i);
				}
			}
		}
	}
	cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

K - Escape Plan(Dijkstra变种)

  • 从终点开始跑最短路,但是只有堆顶出现 d [ u ] d[u] d[u] u u u 之后才能更新 d i s t [ u ] dist[u] dist[u]
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m, k;
	cin >> n >> m >> k;
	vector<int> dist(n + 1, INF), e(k + 1);
	priority_queue<PII, vector<PII>, greater<PII>> pq;
	for (int i = 1; i <= k; i ++ )
	{
		int x; cin >> x;
		e[i] = x;
		pq.push({0, x});
	}
	vector<int> d(n + 1);
	for (int i = 1; i <= n; i ++ ) cin >> d[i];
	for (int i = 1; i <= k; i ++ ) d[e[i]] = 0;
	vector<vector<PII>> g(n + 1);
	for (int i = 1; i <= m; i ++ )
	{
		int u, v, w;
		cin >> u >> v >> w;
		g[u].push_back({v, w});
		g[v].push_back({u, w});
	}
	while (pq.size())
	{
		auto t = pq.top();
		pq.pop();

		int dd = t.first, ver = t.second;
		if (d[ver] <= 0)
		{
			if (dist[ver] > dd) dist[ver] = dd;
			else continue;
		}
		else
		{
			d[ver] -- ;
			continue;
		}

		for (int i = 0; i < g[ver].size(); i ++ )
		{
			int j = g[ver][i].first, w = g[ver][i].second;
			if (dist[j] > dd + w)
			{
				pq.push({dd + w, j});
			}
		}
	}
	if (dist[1] == INF) cout << -1 << '\n';
	else cout << dist[1] << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

L - Digit Product(签到)

  • 每十个数必会出现一个 0,所以直接遍历就行,碰到 0 直接退出
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e6 + 10;
const int maxn = 1e6;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int l, r;
	cin >> l >> r;
	int ans = 1;
	for (int i = l; i <= r; i ++ )
	{
		string s = to_string(i);
		for (auto t : s)
		{
			int num = t - '0';
			if (num == 0)
			{
				cout << 0 << '\n';
				return;
			}
			ans = (ans * num) % mod;
		}
	}
	cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Texcavator

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值