B.有向无环图(CSU 1804)
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 291 Solved: 136
[Submit][Status][Web Board]
Description
Bobo
有一个
n
个点,
为了方便,点用
除以 (109+7) 的余数。
其中, ai,bj 是给定的数列。
Input
输入包含不超过 15 组数据。
每组数据的第一行包含两个整数 n,m(1≤n,m≤105) .
接下来
n
行的第
最后
m
行的第
Output
对于每组数据,输出一个整数表示要求的值。
Sample Input
3 3
1 1
1 1
1 1
1 2
1 3
2 3
2 2
1 0
0 2
1 2
1 2
2 1
500000000 0
0 500000000
1 2
Sample Output
4
4
250000014
题意
中文题,不解释└(^o^)┘!
解题思路
通过对公式 ∑ni=1∑mj=1count(i,j)⋅ai⋅bj 进行化简优化,我们可以通过这个公式将前面一部分 ∑ni=1count(i,j)⋅ai 给求出来,然后一次乘以 bj 就可以得到答案,如何求出前面一部分?
我设置
d[s1]
为当前顶点已经被处理的所有
count(x,s1)
之和,
x
为所有可以到到
代码
时间复杂度: O(|E|)
#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <vector>
#include <cctype>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iomanip>
#include <typeinfo>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define pb push_back
#define mp make_pair
#define mem(a, x) memset(a, x, sizeof(a))
#define copy(a, b) memcpy(a, b, sizeof(a))
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define FIN freopen("input.txt", "r", stdin)
#define FOUT freopen("output.txt", "w", stdout)
typedef long long LL;
typedef pair<int, int > PII;
typedef pair<int, string> PIS;
typedef pair<LL, LL>PLL;
typedef unsigned long long uLL;
template<typename T>
void print (T* p, T* q, string Gap = " ", bool flag = false) {
int d = p < q ? 1 : -1;
while (p != q) {
if (flag) cout << Gap[0] << *p << Gap[1];
else cout << *p;
p += d;
if (p != q && !flag) cout << Gap;
}
cout << endl;
}
template<typename T>
void print (const T &a, string bes = "") {
int len = bes.length();
if (len >= 2) cout << bes[0] << a << bes[1] << endl;
else cout << a << endl;
}
template<typename T>
void debug (T* p, T* q, string Gap = " ", bool flag = false) {
#ifndef ONLINE_JUDGE
int d = p < q ? 1 : -1;
cout << "Debug out : ";
while (p != q) {
if (flag) cout << Gap[0] << *p << Gap[1];
else cout << *p;
p += d;
if (p != q && !flag) cout << Gap;
}
cout << endl;
#endif
}
template<typename T>
void debug (const T &a, string bes = "") {
#ifndef ONLINE_JUDGE
int len = bes.length();
cout << "Debug out : ";
if (len >= 2) cout << bes[0] << a << bes[1] << endl;
else cout << a << endl;
#endif
}
void IO_Init() {
ios::sync_with_stdio (false);
}
LL LLabs (const LL a) {
return a >= 0 ? a : -a;
}
const double PI = 3.1415926535898;
const double eps = 1e-10;
const int MAXM = 1e5 + 5;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
/*头文件模板*/
struct o {
int to, cost, nxt;
} E[MAXN << 1];
int Head[MAXN], tot;
int IN[MAXN], A[MAXN], B[MAXN];
LL D[MAXN];
void init_edge() {
mem(Head, -1);
tot = 0;
mem(IN, 0);
mem(D, 0);
}
void add_edge(int u, int v, int cost) {
E[tot].to = v;
E[tot].cost = cost;
E[tot].nxt = Head[u];
Head[u] = tot ++;
}
int n, m, res;
void topu() {
queue<int>que;
for(int i = 1; i <= n; i ++) {
if(!IN[i]) {
que.push(i);
}
}
while(!que.empty()){
int u = que.front();
que.pop();
for(int v = Head[u]; ~v; v = E[v].nxt){
o &e = E[v];
IN[e.to] --;
D[e.to] = (D[e.to] + D[u] + A[u]) % mod;
if(!IN[e.to]){
que.push(e.to);
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
FIN;
//FOUT;
#endif
IO_Init();
while(~scanf("%d%d", &n, &m)) {
init_edge();
for(int i = 1; i <= n; i ++) {
scanf("%d%d", &A[i], &B[i]);
}
int x, y;
for(int i = 0; i < m; i ++) {
scanf("%d%d", &x, &y);
add_edge(x, y, 1);
IN[y] ++;
}
topu();
LL res = 0;
for(int i = 1;i <= n;i ++){
res = (res + D[i] * B[i] % mod) % mod;
}
printf("%lld\n", res);
}
return 0;
}
G.Parenthesis(CSU 1809)
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 812 Solved: 213
[Submit][Status][Web Board]
Description
Bobo has a balanced parenthesis sequence
P=p1p2…pn
of length
n
and
The
i
-th question is whether
Parenthesis sequence S is balanced if and only if:
S is empty;or there exists balanced parenthesis sequence A,B such that S=AB ;
or there exists balanced parenthesis sequence S′ such that S=(S′) .
Input
The input contains at most 30 sets. For each set:
The first line contains two integers n,q(2≤n≤105,1≤q≤105) .
The second line contains n characters
p1p2…pn .The i -th of the last
q lines contains 2 integersai,bi(1≤ai,bi≤n,ai≠bi) .Output
For each question, output “ Yes ” if P remains balanced, or “
No ” otherwise.Sample Input
4 2
(())
1 3
2 3
2 1
()
1 2Sample Output
No
Yes
No题意
给定一个长度为 n 的由’
( ’和’ ) ’两种字符构成的序列,初始序列时平衡即,左括号和右括号最开始是匹配,然后进行q 次询问,交换 a 和b 两个位置的字符,判断这个序列是否依旧平衡,每一次询问相互独立,互不影响。解题思路
最开始先求解这个字符串的前缀和,’ ( ’代表加
1 ,’ ) ’代表减1 ,很明显,然后我们用线段树维护这个前缀和中的最小值,很明显,当一个序列中的前缀和的最小值小于 0 的话,它一定无法组成一个平衡的序列,因为’) ’括号多了一个,之后不管是加’ ) ’还是’( ’,都无法让前面的’ ) ’找到它匹配的结果,让最终的序列平衡。然后我们针对给定交换两个的位置的字符进行判断,分为以下四种情况,当然这四种情况中
a≤b :当前 a=( , b=) ,交换这两个位置的字符跟没有交换一样,因为整个字符串没有变化,而最开始字符串是平衡的,所以前缀和中不会出现小于 0 的情况,所以输出
Yes .当前 a=) , b=) ,交换这两个位置的字符跟没有交换一样,因为整个字符串没有变化,而最开始字符串是平衡的,所以前缀和中不会出现小于 0 的情况,所以输出
Yes .当前 a=) , b=( ,交换这两个位置的字符是不会得到一个前缀和小于 0 ,因为’
) ’本身是造成减’ 1 ’,如果交换了’( ’,那么就变成加 1 ,而将’) ’换到后方进行减 1 ,很明显这个操作是相互抵消的,同时不会出现小于0 ,所以输出 Yes .当前 a=( , b=) ,正如 3 所说,因为’
( ’本身是造成加’ 1 ’,如果交换了’) ’,那么就变成减 1 ,这一步操作就可能造成前缀和小于0 ,如此我们需要对最小值进行减 2 操作,判断是否会出现小于0 。小于 0 输出No ,不小于 0 输出Yes .
代码
时间复杂度: O(n⋅log(n)+q⋅log(q))
#include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <vector> #include <cctype> #include <cstdio> #include <string> #include <cstring> #include <sstream> #include <cstdlib> #include <iomanip> #include <typeinfo> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define pb push_back #define mp make_pair #define mem(a, x) memset(a, x, sizeof(a)) #define copy(a, b) memcpy(a, b, sizeof(a)) #define lson rt << 1, l, mid #define rson rt << 1|1, mid + 1, r #define FIN freopen("input.txt", "r", stdin) #define FOUT freopen("output.txt", "w", stdout) typedef long long LL; typedef pair<int, int > PII; typedef pair<int, string> PIS; typedef pair<LL, LL>PLL; typedef unsigned long long uLL; template<typename T> void print (T* p, T* q, string Gap = " ", bool flag = false) { int d = p < q ? 1 : -1; while (p != q) { if (flag) cout << Gap[0] << *p << Gap[1]; else cout << *p; p += d; if (p != q && !flag) cout << Gap; } cout << endl; } template<typename T> void print (const T &a, string bes = "") { int len = bes.length(); if (len >= 2) cout << bes[0] << a << bes[1] << endl; else cout << a << endl; } template<typename T> void debug (T* p, T* q, string Gap = " ", bool flag = false) { #ifndef ONLINE_JUDGE int d = p < q ? 1 : -1; cout << "Debug out : "; while (p != q) { if (flag) cout << Gap[0] << *p << Gap[1]; else cout << *p; p += d; if (p != q && !flag) cout << Gap; } cout << endl; #endif } template<typename T> void debug (const T &a, string bes = "") { #ifndef ONLINE_JUDGE int len = bes.length(); cout << "Debug out : "; if (len >= 2) cout << bes[0] << a << bes[1] << endl; else cout << a << endl; #endif } void IO_Init() { ios::sync_with_stdio (false); } LL LLabs (const LL a) { return a >= 0 ? a : -a; } const double PI = 3.1415926535898; const double eps = 1e-10; const int MAXM = 1e5 + 5; const int MAXN = 1e5 + 5; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; /*头文件模板*/ int n, q; int sum[MAXN << 2]; char S[MAXN]; int A[MAXN]; int tot; void pushup(int rt) { sum[rt] = min(sum[rt << 1], sum[rt << 1 | 1]); } void build(int rt, int l, int r) { if(l == r) { sum[rt] = A[tot]; tot ++; return; } int mid = (l + r) >> 1; build(lson); build(rson); pushup(rt); } int query(int L, int R, int rt, int l, int r) { if(L > R) return 0; if(L <= l && r <= R) { return sum[rt]; } int mid = (l + r) >> 1; int res = INF; if(L <= mid) { res = min(res, query(L, R, lson)); } if(mid < R) { res = min(res, query(L, R, rson)); } return res; } int main() { #ifndef ONLINE_JUDGE //FIN; //FOUT; #endif IO_Init(); while(~scanf("%d%d", &n, &q)) { tot = 1; scanf("%s", S); A[0] = 0; int len = strlen(S); for(int i = 0;i < len;i ++){ A[i + 1] = A[i] + (S[i] == '(' ? 1 : -1); } build(1, 1, n); int l, r; for(int i = 0; i < q; i ++) { scanf("%d%d", &l, &r); if(r < l) swap(l, r); int res1 = query(l, r - 1, 1, 1, n); l --, r --; if(S[l] == '(' && S[r] == ')'){ res1 -= 2; } puts(res1 >= 0 ? "Yes" : "No"); } } return 0; }
F.地铁(CSU 1808)
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 668 Solved: 150
[Submit][Status][Web Board]Description
Bobo 居住在大城市 ICPCCamp。
ICPCCamp 有 n 个地铁站,用
1,2,…,n 编号。 m 段双向的地铁线路连接n 个地铁站,其中第 i 段地铁属于ci 号线,位于站 ai,bi 之间,往返均需要花费 ti 分钟(即从 ai 到 bi 需要 ti 分钟,从 bi 到 ai 也需要 ti 分钟)。众所周知,换乘线路很麻烦。如果乘坐第 i 段地铁来到地铁站
s ,又乘坐第 j 段地铁离开地铁站s ,那么需要额外花费 |ci−cj| 分钟。注意,换乘只能在地铁站内进行。Bobo 想知道从地铁站 1 到地铁站
n 所需要花费的最小时间。Input
输入包含不超过 20 组数据。
每组数据的第一行包含两个整数 n,m(2≤n≤105,1≤m≤105) .
接下来 m 行的第
i 行包含四个整数 ai,bi,ci,ti(1≤ai,bi,ci≤n,1≤ti≤109) .保证存在从地铁站 1 到
n 的地铁线路(不一定直达)。Output
对于每组数据,输出一个整数表示要求的值。
Sample Input
3 3
1 2 1 1
2 3 2 1
1 3 1 1
3 3
1 2 1 1
2 3 2 1
1 3 1 10
3 2
1 2 1 1
2 3 1 1Sample Output
1
3
2题意
中文题,不解释└(^o^)┘!
解题思路
这道题目稍微有点坑,如果单纯的使用最短路去求解,每一段地铁针对前段地铁进行判断求解的话,非常不现实 ,总共要求解将近 m2 的结果,针对题目给定的复杂度,傻眼!!!,如此我们需要想新的办法。
拆点构图,这个思路稍微想过,在网络流做过相应的题目,主要的方法是针对每一个进行相应相应的拆点构造,一般是将一个点拆分两个点,然后对于在图中的每一个点的边连接的情况进行重新处理。 [ 此方法会在基本图论方法总结上进行详细解说
] 思路步骤:
首先用拆点构图明确如何拆点连边,拆点连边如下图所示:
我们将中间的点 v 进行拆分为
v1 和 v2 两点,中间的价值为 |c1−c2| 。然后我们就会发现,针对每一个点,只要是和它相连接的顶点我们都需要进行拆分,如下图:
如此就会扩充大量的边,很明显这样是不行的.于是我们就需要对一个顶点相连接的边的数据对 c 进行排序,为什么要对
c 进行排序,如下图:
我们发现,我们可以用 |VZ|+|ZA1| 来代替 |VA1| ,这样我们就可以知道,我们不需要每一个点之间都需要构造边,我们只要构造相邻 c 的边进行构建就可以了。
如此我们就解决了拆点构边的问题。
我们构造点之后,如何进行最短路处理,由于我们进行拆点构边,每一个点都被重构了一次,我们还需要用到多源多汇的原理,从
0 点开始连接所有与顶点为 1 ,边的权值为0 ,同时连接构造点后的总点数与 n ,边的权值为0 , [ 与每一个顶点连接的边的c 的值具有唯一性 ] <script type="math/tex" id="MathJax-Element-5105">]</script>如此题目基本解决,有些不明白的地方可以看代码,里面也有相关讲解。
代码
时间复杂度:
/*头文件模板*/ #include <map> #include <set> #include <cmath> #include <ctime> #include <queue> #include <stack> #include <vector> #include <cctype> #include <cstdio> #include <string> #include <cstring> #include <sstream> #include <cstdlib> #include <iomanip> #include <typeinfo> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define pb push_back #define mp make_pair #define mem(a, x) memset(a, x, sizeof(a)) #define copy(a, b) memcpy(a, b, sizeof(a)) #define lson rt << 1, l, mid #define rson rt << 1|1, mid + 1, r #define FIN freopen("input.txt", "r", stdin) #define FOUT freopen("output.txt", "w", stdout) typedef long long LL; typedef pair<int, int > PII; typedef pair<int, string> PIS; typedef pair<LL, int>PLI; typedef pair<LL, LL>PLL; typedef unsigned long long uLL; template<typename T> void print (T* p, T* q, string Gap = " ", bool flag = false) { int d = p < q ? 1 : -1; while (p != q) { if (flag) cout << Gap[0] << *p << Gap[1]; else cout << *p; p += d; if (p != q && !flag) cout << Gap; } cout << endl; } template<typename T> void print (const T &a, string bes = "") { int len = bes.length(); if (len >= 2) cout << bes[0] << a << bes[1] << endl; else cout << a << endl; } template<typename T> void debug (T* p, T* q, string Gap = " ", bool flag = false) { #ifndef ONLINE_JUDGE int d = p < q ? 1 : -1; cout << "Debug out : "; while (p != q) { if (flag) cout << Gap[0] << *p << Gap[1]; else cout << *p; p += d; if (p != q && !flag) cout << Gap; } cout << endl; #endif } template<typename T> void debug (const T &a, string bes = "") { #ifndef ONLINE_JUDGE int len = bes.length(); cout << "Debug out : "; if (len >= 2) cout << bes[0] << a << bes[1] << endl; else cout << a << endl; #endif } void IO_Init() { ios::sync_with_stdio (false); } LL LLabs (const LL a) { return a >= 0 ? a : -a; } const double PI = 3.1415926535898; const double eps = 1e-10; const int MAXM = 1e5 + 5; const int MAXN = 1e5 + 5; const int INF = 0x3f3f3f3f; /*头文件模板*/ struct Edge{ int to, cost, nxt; }E[MAXN << 3]; struct o{ int c, t, v; o(){} o(int v, int c, int t):v(v), c(c), t(t){} bool operator < (const o &a) const{ return c < a.c; } }; int Head[MAXN << 2], tot; LL d[MAXN << 3]; vector<o>IN[MAXN]; vector<int>C_d[MAXN]; map<int, int>C_d_m[MAXN]; void init_edge(){ mem(Head, -1); tot = 0; for(int i = 0;i < MAXN;i ++){ IN[i].clear(); C_d[i].clear(); C_d_m[i].clear(); } } void add_edge(int u,int v, int cost){ E[tot].to = v; E[tot].cost = cost; E[tot].nxt = Head[u]; Head[u] = tot ++; } void BFS(int s){//最短路,代码不解释,你懂得! priority_queue<PLI, vector<PLI>, greater<PLI> >que; que.push(PLI(0, s)); mem(d, 0x3f); d[s] = 0; while(!que.empty()){ PII p = que.top(); que.pop(); int u = p.second; if(p.first > d[u]) continue; for(int v = Head[u]; ~v; v = E[v].nxt){ Edge &e = E[v]; if(d[e.to] > d[u] + e.cost){ d[e.to] = d[u] + e.cost; que.push(PII(d[e.to], e.to)); } } } } int n, m; int main() { #ifndef ONLINE_JUDGE //FIN; //FOUT; #endif IO_Init(); int u, v, c, t; while(~scanf("%d%d", &n, &m)){ init_edge(); for(int i = 0;i < m;i ++){ scanf("%d%d%d%d", &u, &v, &c, &t); IN[u].pb(o(v, c, t)); IN[v].pb(o(u, c, t)); } int zt = 1; for(int i = 1;i <= n;i ++){ sort(IN[i].begin(), IN[i].end());//对每一个顶点连接的边的$c$进行排序。 for(int j = 0;j < IN[i].size();j ++){ C_d_m[i][IN[i][j].c] = zt;//获取得到每一个c对应的新构造的顶点 C_d[i].pb(zt ++); } } for(int i = 0;i < IN[1].size();i ++){ add_edge(0, C_d[1][i], 0);//连接顶点为0到与1相连的顶点 } for(int i = 0;i < IN[n].size();i ++){ add_edge(C_d[n][i], zt, 0);//连接与n相连接的顶点到zt顶点 } for(int i = 1;i <= n;i ++){ for(int j = 0;j < IN[i].size();j ++){ u = i, v = IN[i][j].v, c = IN[i][j].c, t = IN[i][j].t; add_edge(C_d_m[v][c], C_d[i][j], t);//连接相邻的两个点 if(j >= 1){//开始构造满足条件的边 add_edge(C_d[i][j - 1], C_d[i][j], IN[i][j].c - IN[i][j - 1].c); add_edge(C_d[i][j], C_d[i][j - 1], IN[i][j].c - IN[i][j - 1].c); } } } BFS(0); printf("%lld\n", d[zt]); } return 0; }