#数论、分层最短路# ACM-ICPC 2018 南京赛区网络预赛

版权声明:本文为博主原创文章,转载清注明出处 https://blog.csdn.net/Jasmineaha/article/details/82389011

题目链接

An Olympian Math Problem

Alice, a student of grade 66, is thinking about an Olympian Math problem, but she feels so despair that she cries. And her classmate, Bob, has no idea about the problem. Thus he wants you to help him. The problem is:

We denote k!k!: k! = 1 \times 2 \times \cdots \times (k - 1) \times kk!=1×2×⋯×(k−1)×k

We denote SS: S = 1 \times 1! + 2 \times 2! + \cdots +S=1×1!+2×2!+⋯+(n - 1) \times (n-1)!(n−1)×(n−1)!

Then SS module nn is ____________

You are given an integer nn. You have to calculate SS modulo nn.

Input

The first line contains an integer T(T \le 1000)T(T≤1000), denoting the number of test cases.

For each test case, there is a line which has an integer nn.

It is guaranteed that 2 \le n\le 10^{18}2≤n≤1018.

Output

For each test case, print an integer SS modulo nn.

Solution:

第n次了,一定要记住对于一些数论和DP题,请考虑 打!表!找!规!律!

相加相消可以得出 S(n) = (n! - 1) mod n

所以有S(n) mod n = (n!−1) mod n = (n! + n−1) mod n = n! mod n + (n−1) mod n = n − 1 。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <cstdlib>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#define mst(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MaxN = 1e5 + 5;
 
int main () 
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
 
    int t; cin >> t;
    while(t--) {
		LL n;
		cin >> n;
		cout << n - 1 << endl;
	}
    return 0;
}

Magical Girl Haze

There are NN cities in the country, and MM directional roads from uu to v(1\le u, v\le n)v(1≤u,v≤n). Every road has a distance c_ici​. Haze is a Magical Girl that lives in City 11, she can choose no more than KK roads and make their distances become 00. Now she wants to go to City NN, please help her calculate the minimum distance.

Input

The first line has one integer T(1 \le T\le 5)T(1≤T≤5), then following TT cases.

For each test case, the first line has three integers N, MN,M and KK.

Then the following MM lines each line has three integers, describe a road, U_i, V_i, C_iUi​,Vi​,Ci​. There might be multiple edges between uu and vv.

It is guaranteed that N \le 100000, M \le 200000, K \le 10N≤100000,M≤200000,K≤10,
0 \le C_i \le 1e90≤Ci​≤1e9. There is at least one path between City 11 and City NN.

Output

For each test case, print the minimum distance.

Description:

在m条路中选出k条路将距离变为0,求操作之后的从 1-n 的最短路

Solution:

边去重 + 分层最短路 

分层图主要是应用于变化的最短路问题,问题常表现为一个最短路问题上增加一些操作,如减小一些边权、改变一些连接。由于不清楚具体要对于哪些边进行操作,所以用到分层图思想。 
可以理解为类似平行宇宙,就是把原图复制出来k个,然后在原图连接的基础上,在相邻层中间加一些要求的变化边,通常是单向的(保证从每一层到下一层不再回来),再跑最短路。


分层图最短路,就是在分层图上解决最短路问题。 
一般解决方法是多开一维记录状态,多开的维度记录状态的种类数即为分层数。


多一种情况松弛判断就行,其实和bfs思想相同

相似题目参考: 飞行路线

Code:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define fi first
#define se second
#define mst(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
//typedef pair<int, LL> PIL;
const int INF = 0x3f3f3f3f;
const int Mod = 1e9 + 7;
const int MaxN = 1e5 + 5;
const int MaxM = 2e5 + 5;

struct EDGE{ 
	int u, v, w;
	bool operator < (const EDGE &a) const{
		if(u == a.u && v == a.v) return w < a.w;
		if(u == a.u) return v < a.v;
		return u < a.u;
	}
}edge[MaxM];

struct MAP{
	int to, w, nxt;
}G[MaxN];

struct node{
	LL d;
	int x, k;
	bool operator < (const node &a) const{
		return d > a.d;
	}
};

int n, m, k;
int vis[MaxN][15];
int all, last[MaxN];
LL dist[MaxN][12];

void init() {
	all = 0;
	mst(last, 0);
	mst(G, 0);
	mst(vis, 0);
	for(int i = 0; i < MaxN; i++) 
		for(int j = 0; j <= 10; j++)
			dist[i][j] = 1e18;
}

void build(int u, int v, int w) {
	G[++all].to = v;
	G[all].w = w;
	G[all].nxt = last[u];
	last[u] = all;
}

void Heap_Dij(int s) {
	priority_queue<node> que;
	dist[s][0] = 0;
	que.push((node){0, 1, 0});
	while(!que.empty()) {
		node p = que.top(); que.pop();
		int u = p.x, cnt = p.k;
		if(vis[u][cnt]) continue;
        vis[u][cnt] = 1;
		for(int i = last[u]; i; i = G[i].nxt){
			MAP e = G[i];
			if(dist[e.to][cnt] > dist[u][cnt] + e.w) { //在不进行操作的情况下的松弛,相当于普通dijk
				dist[e.to][cnt] = dist[u][cnt] + e.w;
				if(!vis[e.to][cnt]) que.push((node){dist[e.to][cnt], e.to, cnt});
			}
			if(cnt + 1 <= k && dist[e.to][cnt+1] > dist[u][cnt]) { //如果对当前的边进行操作,然后再进行松弛同上判断是否入队
				dist[e.to][cnt+1] = dist[u][cnt];
				if(!vis[e.to][cnt]) que.push((node){dist[e.to][cnt+1], e.to, cnt+1});
			}
		}
	}
}

int main()
{
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    
    int t; scanf("%d", &t);
    while(t--) {
		scanf("%d %d %d", &n, &m, &k);
    	init();
		for(int i = 1; i <= m; i++)
			scanf("%d %d %d", &edge[i].u, &edge[i].v, &edge[i].w);
		sort(edge + 1, edge + 1 + m);
		int preu = -1, prev = -1;
		for(int i = 1; i <= m; i++) { //对边去重的同时建图
			int u = edge[i].u, v = edge[i].v, w = edge[i].w;
			if(preu != u || prev != v) {
				build(u, v, w);
				preu = u, prev = v;
			}
		}
		Heap_Dij(1);
		LL ans = 1e18;
		for(int i = 0; i <= k; i++) ans = min(ans, dist[n][i]);
		printf("%lld\n", ans);
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Jasmineaha/article/details/82389011