hdu3681 Prison Break
二分+状压DP...
因为懒得写dx和dy导致BFS完全写错...过了样例查不出错 = =
怒而重写BFS就过了,虽然还是没有写dxdy
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second //#pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 20 int n , m , num[N][N] , t[N] , cnt , g[N][N]; char s[N][N]; void BFS(int id , int x) { int i , j , y , d[N][N]; for (i = 0 ; i < n ; ++ i) for (j = 0 ; j < m ; ++ j) d[i][j] = 1 << 30; d[x / m][x % m] = 0; queue<pair<int ,int> > Q; Q.push(mp(x / m , x % m)); while (!Q.empty()){ x = Q.front().fi , y = Q.front().se ; Q.pop(); if (x && s[x - 1][y] != 'D' && d[x - 1][y] == 1 << 30) d[x - 1][y] = d[x][y] + 1 , Q.push(mp(x - 1 , y)); if (y && s[x][y - 1] != 'D' && d[x][y - 1] == 1 << 30) d[x][y - 1] = d[x][y] + 1 , Q.push(mp(x , y - 1)); if (x < n - 1 && s[x + 1][y] != 'D' && d[x + 1][y] == 1 << 30) d[x + 1][y] = d[x][y] + 1 , Q.push(mp(x + 1 , y)); if (y < m - 1 && s[x][y + 1] != 'D' && d[x][y + 1] == 1 << 30) d[x][y + 1] = d[x][y] + 1 , Q.push(mp(x , y + 1)); } for (i = 0 ; i < cnt ; ++ i) g[id][i] = d[t[i] / m][t[i] % m]; } int f[1 << 15][15]; void work() { int i , j , k , l , r , val , res = 0 , ans , st; for (i = 0 ; i < n ; ++ i) scanf("%s" , s[i]); k = cnt = 0; for (i = 0 ; i < n ; ++ i) for (j = 0 ; j < m ; ++ j) { if (s[i][j] == 'F') st = cnt; if (s[i][j] == 'Y') res |= (1 << cnt); if (s[i][j] != 'D' && s[i][j] != 'S') t[cnt ++] = k; num[i][j] = k ++; } for (i = 0 ; i < cnt ; ++ i) BFS(i , t[i]); l = 0 , r = n * m; while (l < r) { val = (l + r) >> 1; memset(f , -1 , sizeof(f)); f[1 << st][st] = val , ans = -1; for (i = 1 ; i < 1 << cnt ; ++ i) { for (j = 0 ; j < cnt ; ++ j) if (f[i][j] >= 0) { if ((i & res) == res) ans = max(ans , f[i][j]); for (k = 0 ; k < cnt ; ++ k) if (~i & (1 << k)) { if (g[j][k] <= f[i][j]) { f[i | (1 << k)][k] = max(f[i | (1 << k)][k] , f[i][j] - g[j][k]); if (~res & (1 << k)) f[i | (1 << k)][k] = val; } } } } if (ans >= 0) r = val; else l = val + 1; } if (l == n * m) l = -1; printf("%d\n" , l); } int main() { std::ios::sync_with_stdio(false); //int _; scanf("%d",&_); while (_--) while (scanf("%d%d",&n,&m) , n || m) work(); return 0; }
好坑的题啊!
Tarjan缩点之后,把BCC都连在对应的割点上,最后形成了一棵割点和BCC交错的树,询问就是两个BCC之间的路径有多少割点,其实就是路径长度/2。
思路很清晰,然后WAWAWAWAWA....
对拍全对找不到错,然后WAWAWAWAWA...
对拍数据里面很良心都没有重边...我就琢磨是不是这个问题..
然后回题面上一看人家也没说没有重边……
把tarjan改了小小的下让它能处理重边,就AC了……一下午的时间加WAx33...._(:3」∠)_
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second #pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 200005 #define M 500005 int n , m , pre[N] , mcnt , id[N]; struct edge { int x , next; }e[M] , g[M << 1]; int pp[N] , cc; int low[N] , DFN[N] , ncnt , bel[M] , bcnt , cutnum , pel[M]; vector<int> bcc[N]; bool iscut[N]; stack< pair<int,int> > S; void tarjan(int x , int fa) { low[x] = DFN[x] = ++ ncnt; int i , y , xx , yy , child = 0; for (i = pre[x] ; ~i ; i = e[i].next) { y = e[i].x; if (!DFN[y]) { S.push(mp(x , i ^ 1)); ++ child; tarjan(y , i); low[x] = min(low[x] , low[y]); if (low[y] >= DFN[x]) { iscut[x] = 1; ++ bcnt , bcc[bcnt].clear(); do { xx = S.top().fi , yy = e[S.top().se].x , pel[(S.top().se >> 1) + 1] = bcnt , S.pop(); if (bel[xx] != bcnt) bcc[bcnt].pb(xx) , bel[xx] = bcnt; if (bel[yy] != bcnt) bcc[bcnt].pb(yy) , bel[yy] = bcnt; }while(x != xx || y != yy); } } else if (DFN[y] < DFN[x] && i != fa) S.push(mp(x , i)) , low[x] = min(DFN[y] , low[x]); } if (fa < 0 && child == 1) iscut[x] = 0; } int f[N][20] , L[N]; bool vis[N]; void dfs(int x , int fa) { f[x][0] = fa , L[x] = L[fa] + 1 , vis[x] = 1; for (int i = pp[x] ; ~i ; i = g[i].next) if (!vis[g[i].x]) dfs(g[i].x , x); } int LCA(int x , int y) { int log , i; if (x == y) return x; if (L[x] < L[y]) swap(x , y); for (log = 1 ; (1 << log) <= L[x] ; ++ log); -- log; for (i = log ; i >= 0 ; -- i) if (L[x] - (1 << i) >= L[y]) x = f[x][i]; if (x == y) return y; for (i = log ; i >= 0 ; -- i) if (f[x][i] && f[y][i] && f[x][i] != f[y][i]) x = f[x][i] , y = f[y][i]; return f[x][0]; } void work() { int i , j , x , y , z; memset(pre , -1 , sizeof(pre)); memset(pp , -1 , sizeof(pp)); mcnt = bcnt = ncnt = cc = 0 ; while (m --) { scanf("%d%d",&x,&y); e[mcnt].x = y , e[mcnt].next = pre[x] , pre[x] = mcnt ++; e[mcnt].x = x , e[mcnt].next = pre[y] , pre[y] = mcnt ++; } memset(low , 0 , sizeof(low)); memset(DFN , 0 , sizeof(DFN)); memset(iscut , 0 , sizeof(iscut)); memset(bel , 0 , sizeof(bel)); memset(L , 0 , sizeof(L)); memset(id , 0 , sizeof(id)); memset(pel , 0 , sizeof(pel)); for (i = 1 ; i <= n ; ++ i) if (!DFN[i]) tarjan(i , -1); cutnum = bcnt; for (i = 1 ; i <= n ; ++ i) if (iscut[i]) id[i] = ++ cutnum; for (j = 1 ; j <= bcnt ; ++ j) { for (i = 0 ; i < bcc[j].size() ; ++ i) if (iscut[y = bcc[j][i]]) { y = id[y] , x = j; //cout << x << ' ' << y << endl; g[cc].x = y , g[cc].next = pp[x] , pp[x] = cc ++; g[cc].x = x , g[cc].next = pp[y] , pp[y] = cc ++; } } memset(f , 0 , sizeof(f)); memset(vis , 0 , sizeof(vis)); for (i = 1 ; i <= cutnum ; ++ i) if (!vis[i]) dfs(i , 0); for (j = 1 ; 1 << j <= cutnum ; ++ j) for (i = 1 ; i <= cutnum ; ++ i) f[i][j] = f[f[i][j - 1]][j - 1]; scanf("%d",&m); while (m --) { scanf("%d%d",&x ,&y); x = pel[x] , y = pel[y]; //cout << x << ' ' << y << endl; z = LCA(x , y); printf("%d\n" , (L[x] + L[y] - L[z] - L[z]) >> 1); } //cout << endl; } int main() { while (scanf("%d%d",&n,&m) , n || m) work(); return 0; }
KMP处理一下状态转移就可以直接DP了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second #pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 25 int n , m; double p[N] , d[1001][N]; char str[N] , s[N]; int f[N]; void work() { int i , j , k , l; double x , y; memset(p , 0 , sizeof(p)); for (i = 1 ; i <= n ; ++ i) { scanf("%s %lf" , str , &x); p[*str - 'a'] = x; } scanf("%s" , s); n = strlen(s); f[0] = f[1] = 0; for (i = 1 ; i < n ;i ++) { int j = f[i]; while (j && s[i] != s[j]) j = f[j]; f[i + 1] = s[i] == s[j] ? j + 1 : 0; } memset(d , 0 , sizeof(d)); d[0][0] = 1; for (i = 0 ; i < m ; ++ i) { for (j = 0 ; j < n ; ++ j) if (d[i][j] > 0) { for (k = 0 ; k < 26 ; ++ k) if (p[k] > 0) { l = j; while (l && k != s[l] - 'a') l = f[l]; if (k == s[l] - 'a') ++ l; d[i + 1][l] += d[i][j] * p[k]; } } d[i + 1][n] += d[i][n]; } printf("%.2f%%\n" , d[m][n] * 100 + 1e-9); } int main() { //std::ios::sync_with_stdio(false); //int _; scanf("%d",&_); while (_--) while (scanf("%d%d",&n,&m) , n || m) work(); return 0; }
全局最小割,源点没有意义。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second #pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 305 #define M 500005 int n , m , d[N] , g[N][N] , ans; bool f[N] , u[N]; void find(int& s , int& t) { int i , j , x; memset(u , 0 , sizeof(u)); memset(d , 0, sizeof(d)); for (i = 0 ;i < n ; ++ i) { x = -1; for (j = 0 ;j < n ;j ++) if (!u[j] && !f[j] && (d[j] > d[x] || x == -1)) x = j; if (x == -1) {ans = min(ans , t == -1 ? 1 << 30 : d[t]); return;} u[x] = 1 , s = t , t = x; for (j = 0 ;j < n ;j ++) if (!u[j] && !f[j]) d[j] += g[x][j]; } ans = min(ans , d[t]); } void work() { int i , j , x , y , z; ans = 1 << 30; memset(g , 0, sizeof(g)); for (i = 1 ; i <= m ;i ++) { scanf("%d%d%d",&x,&y,&z); -- x , -- y; g[x][y] += z , g[y][x] += z; } memset(f , 0, sizeof(f)); for (i = 1 ; i < n ;i ++) { x = y = -1 , find(x , y); f[y] = 1; for (j = 0 ; j < n ; ++ j) g[x][j] += g[y][j] , g[j][x] += g[j][y]; } cout << ans << endl; } int main() { //std::ios::sync_with_stdio(false); while (scanf("%d%d%d",&n,&m ,&ans) , n || m) work(); return 0; }
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second #pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 250000 #define M 500005 char str[5100005] , tmp[5100005]; int ans; bool bel[255]; struct ACautom { int sum; int u[N][26]; int v[N] , f[N] , l[N]; void clear() { sum = 1 , v[0] = 0; memset(u[0] , 0 , sizeof(u[0])); } void insert(int k) { int x = 0 ; for (int i = 0 ; str[i] ; i ++) { int c = str[i] - 'A'; if (!u[x][c]) { memset(u[sum] , 0 , sizeof(u[sum])); v[sum] = 0; u[x][c] = sum ++; } x = u[x][c]; } v[x] = k; } void getFail() { queue<int> q; f[0] = 0; for (int i = 0 ; i < 26 ; i ++) { int x = u[0][i]; if (x) f[x] = 0 , q.push(x) , l[x] = 0; } while (!q.empty()) { int x = q.front() ; q.pop(); for (int i = 0 ; i < 26 ; ++ i) if (u[x][i]) { int y = u[x][i]; q.push(y); int j = f[x]; while (j && !u[j][i]) j = f[j]; f[y] = u[j][i]; l[y] = v[f[y]] ? f[y] : l[f[y]]; } } } void print(int i , int j) { if (j) { if (!bel[v[j]]) bel[v[j]] = 1 , ++ ans; print(i , l[j]); } } void find() { int j = 0; for (int i = 0 ; str[i] ; ++ i) { int c = str[i] - 'A'; while (j && !u[j][c]) j = f[j]; j = u[j][c]; if (v[j] && !bel[v[j]]) print(i , j); else if (l[j] && !bel[v[l[j]]]) print(i , l[j]); } } }t; int n ; void work() { int i , j , x , len = 0; scanf("%d",&n); t.clear(); for (i = 1 ; i <= n ; ++ i) scanf("%s" , str) , t.insert(i); t.getFail(); scanf("%s" , tmp); memset(bel , 0 , sizeof(bel)) , ans = 0; for (i = 0 ; tmp[i] ; ++ i) { if (tmp[i] == '[') { x = 0; for (j = i + 1 ; isdigit(tmp[j]) ; ++ j) x = x * 10 + tmp[j] - '0'; while (x --) str[len ++] = tmp[j]; i = ++ j; } else str[len ++] = tmp[i]; } str[len] = 0; t.find(); reverse(str , str + len); t.find(); printf("%d\n" , ans); } int main() { int _; scanf("%d",&_); while (_--) work(); return 0; }
给出的是一个DAG,逆向建图可以DP出每个物品可以卖出的最大单价。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second #pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 50005 #define M 100005 int n , m , pre[N] , mcnt , d[N]; struct edge { int x ; double w; int next; }e[M]; double p[N] , w[N]; void work() { int i , x , y; double z; for (i = 1 ; i <= n ; ++ i) scanf("%lf%lf" , &p[i] , &w[i]); memset(pre , -1 , sizeof(pre)) , mcnt = 0; scanf("%d",&m); while (m --) { scanf("%d%d",&i,&x), -- i; while (i --) { scanf("%lf%d" , &z , &y); e[mcnt] = (edge){x , z , pre[y]} , pre[y] = mcnt ++ , ++ d[x]; x = y; } } double ans = 0; queue<int> Q; for (i = 1 ; i <= n ; ++ i) if (!d[i]) Q.push(i); while (!Q.empty()) { x = Q.front() , Q.pop(); ans += p[x] * w[x]; for (i = pre[x] ; ~i ; i = e[i].next) { y = e[i].x , z = e[i].w; p[y] = max(p[y] , p[x] * z); if (!-- d[y]) Q.push(y); } } printf("%.2f\n" , ans); } int main() { //std::ios::sync_with_stdio(false); //int _; scanf("%d",&_); while (_--) while (scanf("%d" , &n) , n) work(); return 0; }
范围很良心..可以直接暴力贪心,每次选择能选择的结束时间最小的课程。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second #pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 1005 #define M 100005 int n; pair<int , int> a[N]; bool f[N]; void work() { int i , j , k , sum , ans = 0 , x; for (i = 1 ; i <= n ; ++ i) scanf("%d%d",&a[i].fi , &a[i].se); for (k = 0 ; k < 5 ; ++ k) //[) { memset(f , 0 , sizeof(f)) , sum = 0; for (j = k ; j <= 1000 ; j += 5) { x = -1; for (i = 1 ; i <= n ; ++ i) if (!f[i] && a[i].fi <= j && j < a[i].se) { if (x == -1 || a[x].se > a[i].se) x = i; } if (~x) ++ sum , f[x] = 1; } ans = max(sum , ans); } printf("%d\n" , ans); } int main() { //std::ios::sync_with_stdio(false); //int _; scanf("%d",&_); while (_--) while (scanf("%d" , &n) , n) work(); return 0; }
DP,然后拿线段树优化一下转移。
这样写是不是有点太暴力了……导致常数巨大一直TLE
尝试了一下读入优化,就过了QAQ……不管了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second #pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 5005 #define M 105 int n , m , a[M][N] , f[M][N]; int id(int l , int r) {return l + r | l != r;} #define ID id(l , r) #define MID int mid = (l + r) >> 1 #define Left l , mid #define Right mid + 1 , r pair<int , int> t1[N << 1] , t2[N << 1]; pair<int , int> *cur = t1 , *past = t2; void buildtree(pair<int , int>* t , int l , int r) { t[ID] = make_pair(1 << 30 , 1 << 30); if (l != r){ MID ; buildtree(t , Left) , buildtree(t , Right);} } void pushup(pair<int , int>* t , int l , int r) { MID; int p = ID , LL = id(Left) , RR = id(Right); t[p].fi = min(t[LL].fi , t[RR].fi); } void pushdown(pair<int , int>* t , int l , int r) { if (t[ID].se == 1 << 30) return; MID; int p = ID , LL = id(Left) , RR = id(Right); t[LL].fi = min(t[LL].fi , t[p].se) , t[LL].se = min(t[LL].se , t[p].se); t[RR].fi = min(t[RR].fi , t[p].se) , t[RR].se = min(t[RR].se , t[p].se); t[p].se = 1 << 30; } void update(pair<int , int>* t , int l , int r , int top , int bot , int w) { if (top <= l && r <= bot){ int p = ID; t[p].fi = min(t[p].fi , w) , t[p].se = min(t[p].se , w); return;} pushdown(t , l , r) ; MID; if (top <= mid) update(t , Left , top , bot , w); if (bot > mid) update(t , Right , top , bot , w); pushup(t , l , r); } int query(pair<int , int>* t , int l , int r , int top , int bot) { if (top <= l && r <= bot) return t[ID].fi; pushdown(t , l , r) ; MID; int res = 1 << 30; if (top <= mid) res = min(query(t , Left , top , bot) , res); if (bot > mid) res = min(query(t , Right , top , bot) ,res); pushup(t , l , r); return res; } void RD(int& x) { x = 0; char c; for (c = getchar() ;!isdigit(c) ; c = getchar()); x = c - '0'; for (c = getchar() ; isdigit(c) ; c = getchar()) x = x * 10 + c - '0'; } void work() { int i , j , l , r , x; for (i = 1 ; i <= n ; ++ i) for (j = 1 ; j <= m ; ++ j) RD(a[i][j]); for (i = 1 ; i <= n ; ++ i) for (j = 1 ; j <= m ; ++ j) RD(f[i][j]); cur = t1 , past = t2; update(past , 1 , m , 1 , m , 0); for (i = 1 ; i <= n ; ++ i) { buildtree(cur , 1 , m); for (j = 1 ; j <= m ; ++ j) { l = max(1 , j - f[i][j]) , r = min(m , j + f[i][j]); x = query(past , 1 , m , l , r) + a[i][j]; update(cur , 1 , m , l , r , x); } swap(past , cur); } printf("%d\n" , query(past , 1 , m , 1 , m)); } int main() { while (RD(n) , RD(m) , n || m) work(); return 0; }
枚举!挺好玩的题……
要注意就是除是带小数的除,除数不能为0,每个字母代表的数字都不一样。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cstdlib> #include <cmath> #include <cctype> #include <queue> #include <stack> #include <map> #include <set> #include <list> #define pb push_back #define mp make_pair #define fi first #define se second //#pragma comment(linker, "/STACK:16777216") using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 15 char s1[N] , s2[N] , s3[N]; int power[N] , a[N] , ans; bool f[N]; void cal() { int i , j , x = 0 , y = 0 , z = 0; for (i = 0 ; i < 5 ; ++ i) if (f[i]) for (j = i + 1 ; j < 5 ; ++ j) if (f[j] && a[i] == a[j]) return; for (i = 0 ; s1[i] ; ++ i) x = x * 10 + a[s1[i] - 'A']; for (i = 0 ; s2[i] ; ++ i) y = y * 10 + a[s2[i] - 'A']; for (i = 0 ; s3[i] ; ++ i) z = z * 10 + a[s3[i] - 'A']; if (strlen(s1) > 1 && !a[s1[0] - 'A']) return; if (strlen(s2) > 1 && !a[s2[0] - 'A']) return; if (strlen(s3) > 1 && !a[s3[0] - 'A']) return; if (x + y == z) ++ ans; //, printf("%d+%d=%d\n" , x ,y , z); if (x - y == z) ++ ans; //, printf("%d-%d=%d\n" , x ,y , z); if (x * y == z) ++ ans; //, printf("%d*%d=%d\n" , x ,y , z); if (y && x == y * z) ++ ans; //, printf("%d/%d=%d\n" , x ,y , z); } void work() { int i , j; ans = 0; scanf("%s%s%s",s1,s2,s3); memset(f , 0 , sizeof(f)); for (i = 0 ; s1[i] ; ++ i) f[s1[i] - 'A'] = 1; for (i = 0 ; s2[i] ; ++ i) f[s2[i] - 'A'] = 1; for (i = 0 ; s3[i] ; ++ i) f[s3[i] - 'A'] = 1; for (a[0] = 0 ; a[0] <= 9 * f[0] ; ++ a[0]) for (a[1] = 0 ; a[1] <= 9 * f[1] ; ++ a[1]) for (a[2] = 0 ; a[2] <= 9 * f[2] ; ++ a[2]) for (a[3] = 0 ; a[3] <= 9 * f[3] ; ++ a[3]) for (a[4] = 0 ; a[4] <= 9 * f[4] ; ++ a[4]) cal(); printf("%d\n" , ans); } int main() { int _; scanf("%d",&_); while (_--) work(); return 0; }