ACM-图论-同余最短路
https://www.cnblogs.com/31415926535x/p/11692422.html
一种没见过的处理模型,,记录一下,,主要是用来处理一个多元一次方程的解的数量的问题,,数据量小时可以用看成背包处理,,数据很大时可以转换成最短路模型+一点数学来处理,,(体积模域下的最短路的问题,,求的一个最简的表示形式有模数来得到所有解
墨墨的等式
因为只是求满足的解的数量,,所以可以将方程转换成一个模方程组,,这样的方程组的解显然也是原来的解的子集,,同时可以利用模数来得到所有解,,
模数的选择是最小的那个系数,,因为如果任意选择,,会出现一些多考虑的情况
弄 mi 个点,表示从0到mi-1的所有数,,建边的方法是 i->(i+a[j])%mi
边权为 a[j] ,,表示从i这个点变成后面一个数的费用,,(因为两边都是取模的,,所以每一个数取几次后的和的余数就是那些经过的点,,也就是说一条路径就是得到一个右边为 i(mod mi) 的一个最小解,,这个最小的解就是费用和,,也就是一条最短路dis[i]
这样我们对于每一个取模的右边的B都计算一下区间里的数量,,,(计算这玩意推错了一次,,emmm
#include <bits/stdc++.h>
#define aaa cout<<233<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(TM(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 3e6 + 5;
const int maxm = 1e7 + 233;
const int mod = 1e9 + 7;
ll n, l, r, a[maxn];
struct edge
{
int to, nxt; ll w;
}edge[maxn << 1];
int tot, head[maxn << 1];
void init()
{
tot = 0;
memset(head, -1, sizeof head);
}
void addedge(int u, int v, ll w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot++;
}
struct node
{
int v; ll w;
node(){}
node(int _v, ll _w):v(_v), w(_w){}
const bool operator<(const node &r)const{
return w > r.w;
}
}tmp;
ll dis[maxn];
bool vis[maxn];
void dijkstra(int s)
{
memset(dis, inf, sizeof dis);
memset(vis, false, sizeof vis);
priority_queue<node> q;
while(!q.empty())q.pop();
q.push(node(s, 0));
dis[s] = 0;
while(!q.empty())
{
tmp = q.top(); q.pop();
if(vis[tmp.v])continue;
vis[tmp.v] = true;
for(int i = head[tmp.v]; ~i; i = edge[i].nxt)
{
int v = edge[i].to;
if(dis[v] > dis[tmp.v] + edge[i].w)
{
dis[v] = dis[tmp.v] + edge[i].w;
q.push(node(v, dis[v]));
}
}
}
}
int main()
{
// double pp = clock();
// freopen("233.in", "r", stdin);
// freopen("233.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> n >> l >> r;
for(int i = 1; i <= n; ++i)cin >> a[i];
sort(a + 1, a + 1 + n);
int mi = a[1];
init();
for(int i = 0; i <= mi - 1; ++i)
for(int j = 1; j <= n; ++j)
addedge(i, (i + a[j]) % mi, a[j]);
dijkstra(0);
ll ans = 0;
for(int i = 0; i <= mi - 1; ++i)
{
if(dis[i] <= r)
{
if(dis[i] == 0)dis[i] = mi;
ans += (r - dis[i]) / mi + 1;
if(l > dis[i])ans -= (l - dis[i] - 1) / mi + 1;
}
}
cout << ans << endl;
return 0;
}
P3403 跳楼机
比上面那个简单些,,就是注意细节,,从1开始,,有一个是1那么值一定是h,,,
#include <bits/stdc++.h>
#define aaa cout<<233<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(TM(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 3e6 + 5;
const int maxm = 1e7 + 233;
const int mod = 1e9 + 7;
ll n, l, r, a[maxn];
struct edge
{
int to, nxt; ll w;
}edge[maxn << 1];
int tot, head[maxn << 1];
void init()
{
tot = 0;
memset(head, -1, sizeof head);
}
void addedge(int u, int v, ll w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot++;
}
struct node
{
int v; ll w;
node(){}
node(int _v, ll _w):v(_v), w(_w){}
const bool operator<(const node &r)const{
return w > r.w;
}
}tmp;
ll dis[maxn];
bool vis[maxn];
void dijkstra(int s)
{
memset(dis, inf, sizeof dis);
memset(vis, false, sizeof vis);
priority_queue<node> q;
while(!q.empty())q.pop();
q.push(node(s, 0));
dis[s] = 1;
while(!q.empty())
{
tmp = q.top(); q.pop();
if(vis[tmp.v])continue;
vis[tmp.v] = true;
for(int i = head[tmp.v]; ~i; i = edge[i].nxt)
{
int v = edge[i].to;
if(dis[v] > dis[tmp.v] + edge[i].w)
{
dis[v] = dis[tmp.v] + edge[i].w;
q.push(node(v, dis[v]));
}
}
}
}
int main()
{
// double pp = clock();
// freopen("233.in", "r", stdin);
// freopen("233.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> n;
for(int i = 1; i <= 3; ++i)cin >> a[i];
sort(a + 1, a + 1 + 3);
if(a[1] == 1){
cout << n << endl;
return 0;
}
ll mi = a[1];
init();
for(int i = 0; i <= mi - 1; ++i)
for(int j = 2; j <= 3; ++j)
addedge(i, (i + a[j]) % mi, a[j]);
dijkstra(1);
ll ans = 0;
for(int i = 0; i <= mi - 1; ++i)
if(dis[i] <= n)
ans += (n - dis[i]) / mi + 1;
cout << ans << endl;
return 0;
}
遥远的旅途
这题的大致思路是将dp问题用最短路来优化,,
设 dp[i][j]
表示从起点走到i时的长度为j的一条路是否存在,,但是空间都会爆掉,,
考虑第二维,假设是通过经过若干个环来达到T,,也就是 len+kw==T
,,这里的w即为环的长度的两倍,,如果取模w就是 len%w==T%w
,,这样子dp方程就变成了到达 i 点时路径长度取模等于j的一条路径的长度,,利用spfa来转移,,只要最后 dp[n][T%w] <= T
就表示存在解,这样子利用模数来压缩了状态,,找等同的就行了,,,参考 参考
#include <bits/stdc++.h>
#define aaa cout<<233<<endl;
#define endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
// mt19937 rnd(TM(0));
const int inf = 0x3f3f3f3f;//1061109567 > 1e9
const ll linf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-6;
const double pi = 3.14159265358979;
const int maxn = 1e2 + 5;
const int maxm = 1e7 + 233;
const int mod = 1e9 + 7;
ll n, m, T, a[maxn], ww;
struct edge
{
int to, nxt; ll w;
}edge[maxn << 1];
int tot, head[maxn << 1];
void init()
{
tot = 0;
memset(head, -1, sizeof head);
}
void addedge(int u, int v, ll w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot++;
}
ll dp[maxn][20005];
bool vis[maxn][20005];
queue<pair<int, ll> > q;
void spfa()
{
memset(dp, inf, sizeof dp);
memset(vis, false, sizeof vis);
while(!q.empty())q.pop();
dp[1][0] = 0; vis[1][0] = true;
q.push(make_pair(1, 0));
while(!q.empty())
{
int u = q.front().first; ll w = q.front().second; q.pop();
vis[u][w] = false;
for(int i = head[u]; ~i; i = edge[i].nxt)
{
int v = edge[i].to; ll vw = edge[i].w;
if(dp[v][(w + vw) % ww] > dp[u][w] + vw)
{
dp[v][(w + vw) % ww] = dp[u][w] + vw;
if(!vis[v][(w + vw) % ww])
{
vis[v][(w + vw) % ww] = true;
q.push(make_pair(v, (w + vw) % ww));
}
}
}
}
}
int main()
{
// double pp = clock();
// freopen("233.in", "r", stdin);
// freopen("233.out", "w", stdout);
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int t; cin >> t;
while(t--)
{
cin >> n >> m >> T;
int u, v, w;
init();
for(int i = 1; i <= m; ++i)
{
cin >> u >> v >> w;
++u, ++v;
addedge(u, v, w);
addedge(v, u, w);
}
bool flag = false;
for(int i = head[n]; ~i; i = edge[i].nxt)
{
ww = edge[i].w << 1;
spfa();
if(dp[n][T % ww] <= T)
{
flag = true;
break;
}
}
if(flag)cout << "Possible" << endl;
else cout << "Impossible" << endl;
}
return 0;
}
(end)
ACM-图论-同余最短路的更多相关文章
- 【66测试20161115】【树】【DP_LIS】【SPFA】【同余最短路】【递推】【矩阵快速幂】
还有3天,今天考试又崩了.状态还没有调整过来... 第一题:小L的二叉树 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣.所以,小L当时卡在了二叉树. ...
- [CF986F]Oppa Funcan Style Remastered[exgcd+同余最短路]
题意 给你 \(n\) 和 \(k\) ,问能否用 \(k\) 的所有 \(>1\) 的因子凑出 \(n\) .多组数据,但保证不同的 \(k\) 不超过 50 个. \(n\leq 10^{1 ...
- HDU 6071 Lazy Running (同余最短路 dij)
Lazy Running Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)To ...
- BZOJ 2118 墨墨的等式 (同余最短路)
题目大意:已知B的范围,求a1x1+a2x2+...+anxn==B存在非负正整数解的B的数量,N<=12,ai<=1e5,B<=1e12 同余最短路裸题 思想大概是这样的,我们选定 ...
- 洛谷P3403跳楼机(最短路构造/同余最短路)
题目-> 解题思路: 最短路构造很神啊. 先用前两个值跑在第三个值模意义下的同余最短路(这步贪心可以证明,如果第三步长为z,那么如果n+z可以达到,n+2z同样可以达到) 最后计算与楼顶差多少个 ...
- 【CodeChef】LECOINS(同余最短路,背包DP)
题意:给定n个物品,每个物品可以取无限次,每个物品有两种属性:价值v和颜色c 现在有q个询问,每次询问是否能取出价值和为S的方案,如有多解输出不同颜色种数的最大值 题意:看到BZOJ评论区有好心人说C ...
- 【同余最短路】洛谷 P2662 牛场围栏
关于同余最短路的部分 [同余最短路]P3403跳楼机/P2371墨墨的等式 [P2662牛场围栏] 题目背景 小L通过泥萌的帮助,成功解决了二叉树的修改问题,并因此写了一篇论文, 成功报送了叉院(羡慕 ...
- 【同余最短路】【例题集合】洛谷P3403 跳楼机/P2371 墨墨的等式
接触到的新内容,[同余最短路]. 代码很好写,但思路不好理解. 同余最短路,并不是用同余来跑最短路,而是通过同余来构造某些状态,从而达到优化时间空间复杂度的目的.往往这些状态就是最短路中的点,可以类比 ...
- Codeforces 516E - Drazil and His Happy Friends(同余最短路)
Codeforces 题面传送门 & 洛谷题面传送门 首先思考一个非常简单的性质:记 \(d=\gcd(n,m)\),那么每次在一起吃完饭的男女孩编号必定与 \(d\) 同余,而根据斐蜀定理可 ...
- Codeforces 986F - Oppa Funcan Style Remastered(同余最短路)
Codeforces 题面传送门 & 洛谷题面传送门 感谢此题教会我一个东西叫做同余最短路(大雾 首先这个不同 \(k\) 的个数 \(\le 50\) 这个条件显然是让我们对每个 \(k\) ...
随机推荐
- 【LeetCode】[0002] 【两数之和】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 给出两个非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字.如果 ...
- Java 调式、热部署、JVM 背后的支持者 Java Agent
我们平时写 Java Agent 的机会确实不多,也可以说几乎用不着.但其实我们一直在用它,而且接触的机会非常多.下面这些技术都使用了 Java Agent 技术,看一下你就知道为什么了. -各个 J ...
- Flink文章测试
Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 Flink文章测试 ...
- Net基础篇_学习笔记_第十一天_面向对象(构造函数)
VS封装字段快捷键: 提取方法 Ctrl+R,M 封装字段 Ctrl+R,E 提取接口 Ctrl+R,I. 构成函数: public Student() { Con ...
- 来几道水题 d050: 妳那裡現在幾點了?
减去15即可(注意这个数小于15的情况) 题目:珊珊到了美国犹他州的杨百翰大学之后,文文禁不住对她的思念,常常想打电话给她,却又担心在美国的她是不是在睡觉.好不容易鼓起勇气打通了电话,第一句就先问:「 ...
- struts2表单提单细节处理
1. 上传文件 大部分项目避免不了要上传文件. struts2提供了封闭的上传文件的入口, 网络上也存在大量的插件用于网页表单中上传文件. 由于自己习惯用SSH框架, 所以介绍一下struts2中文件 ...
- 集群某节点DataNode服务无法启动解决(报java.net.BindException:Address already in use错误)
现象: 在集群中某节点, 启动DataNode服务后马上又Shutdown, 在操作系统没看到有DataNode的日志(可能是服务启动失败, 自动删除了日志文件),幸好在界面上可以查看报错的日志: ...
- HTTP协议的运行流程
1.HTTP协议的流程是什么样的呢? (1)http客户端发起请求,创建端口 (2)http服务器在端口监听客户端请求 (3)http服务器向客户端返回状态和内容 更详细的请参考大神:https:// ...
- ##发送post时,设置了utf-8,中文还是乱码?
发送post时,设置了utf-8,中文还是乱码? 我们用HttpUrlConnection或HttpClient发送了post请求,其中有中文,虽然我们两边都设置了utf-8,但还是乱码? 我们在re ...
- kubernetes实战(二十六):kubeadm 安装 高可用 k8s v1.16.x dashboard 2.x
1.基本配置 基本配置.内核升级.基本服务安装参考https://www.cnblogs.com/dukuan/p/10278637.html,或者参考<再也不踩坑的Kubernetes实战指南 ...