题解
链接:https://codeforces.ml/gym/294361/problem/A
题目冗长傻逼。其实很简单,但是如果用spfa有可能会爆栈,所以我们可以通过打标记的方法来解决;
但是打标记不是很稳定;
所以考虑dp
这个其实有点像背包dp,相当于在一个容积下的最小体积。
#include <iostream> #include <string> #include <cstring> #include <algorithm> #include <cstdio> #include <cctype> #include <queue> #include <stdlib.h> #include <cstdlib> #include <math.h> #include <set> #include <vector> #define inf 107374182 #define N 1010 #define M 10010001 #define ll int #define PII pair<int,int> using namespace std; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } inline ll Max(ll a,ll b){return a>b?a:b;} inline ll Min(ll a,ll b){return a<b?a:b;} int price[N]; int dist[N][N]; int cost[N][N]; struct Node1{ int x,y; }node1[N]; int head[N],edgenum; vector<PII> G[N]; vector<PII> P[N]; int n,maxcost,dp[N][N]; int vis[N][N]; const int INF = (int)1e9; int get_dist(int u,int v){ return ceil(sqrt((node1[u].x - node1[v].x) * (node1[u].x - node1[v].x) + (node1[u].y - node1[v].y) * (node1[u].y - node1[v].y))); } int main() { int i,m,u,v,d,w; node1[0].x = read(); node1[0].y = read(); node1[1].x = read(); node1[1].y = read(); maxcost = read(); maxcost ++; price[0] = read(); int T = read(); for(int i = 1; i <= T;i ++) price[i] = read(); n = read(); for(int i = 2;i < n + 2; i ++){ node1[i].x = read(); node1[i].y = read(); int t = read(); while(t --){ int x1 = read(),y1 = read();x1 += 2; P[i].push_back({x1,y1}); P[x1].push_back({i,y1}); } } for (int i = 1; i < n + 2; i++) { P[0].push_back({i, 0}); if (i > 1) P[i].push_back({1, 0}); } n += 2; for(int i = 0; i < n; i ++){ for(int j = 0; j < n; j ++){ dist[i][j] = get_dist(i,j); } } for (int i = 0; i <= n; i++) for (int j = 0; j <= maxcost; j++) dp[i][j] = INF; dp[0][0] = 0; for(int d = 0; d < maxcost; d ++){ for(int v = 0; v < n; v ++){ if(dp[v][d] >= INF) continue; for(int j = 0; j < P[v].size(); j ++){ PII e = P[v][j]; int u = e.first; int t = e.second; int d2 = dist[v][u] + d; if(d2 >= maxcost) continue; dp[u][d2] = min(dp[u][d2], dp[v][d] + dist[v][u] * price[e.second]); } } } int ans = INF; for (int i = 0; i < maxcost; i++) ans = min(ans, dp[1][i]); if (ans == INF) printf("-1\n"); else printf("%d\n", ans); return 0; }
链接:https://codeforces.ml/gym/294123/problem/L
我们可以预处理每个格子能到哪些格子并全部保存下来。
这样就相当于得到了一张图,在到图上进行bfs找最短路即可,注意保存路径。
因为要求字符串最小,所以还需要注意顺序。
#include"stdio.h" #include"string.h" #include"stack" #include"map" #include"math.h" #include"iostream" #include"vector" #include"queue" #include"algorithm" using namespace std; #define OK printf("\n"); #define Debug printf("this_ok\n"); #define INF 1e18 typedef long long ll; #define scanll(a,b) scanf("%lld%lld",&a,&b); #define scanl(a) scanf("%lld",&a); #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a); #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a); typedef pair<int,int> PII; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } const ll mod = 998244353; const int N = 2010,M = 300010; const double pi = acos(-1); int n,m,sx,sy,ex,ey; char str[N][N]; int G[4][N][N]; int vis[N][N]; int dis[N][N]; PII path[N][N]; int dir[N][N]; queue<PII> Q; void bfs(){ Q.push({sx,sy}); dis[sx][sy] = 1; while(!Q.empty()){ PII P = Q.front(); Q.pop(); // printf("%d %d\n",P.first,P.second); for(int i = 0; i < 4; i ++){ int x = P.first,y = P.second; if(i == 0 || i == 3) x = G[i][P.first][P.second]; else y = G[i][P.first][P.second]; if(x == 0 || y == 0 || str[x][y] == 'X') continue; if(dis[x][y]) continue; dis[x][y] = dis[P.first][P.second] + 1; dir[x][y] = i; path[x][y] = P; Q.push({x,y}); } } } int main(){ n = read(),m = read(); for(int i = 1; i <= n;i ++){ scanf("%s",str[i] + 1); for(int j = 1; j <= m; j ++){ if(str[i][j] == 'S'){ sx = i; sy = j; } if(str[i][j] == 'E'){ ex = i; ey = j; } } } str[sx][sy] = str[ex][ey] = '.'; for(int i = n - 1; i >= 1; i --){ for(int j = 1; j <= m; j ++){ if(str[i + 1][j] == 'X') G[0][i][j] = G[0][i + 1][j]; else G[0][i][j] = i + 1; } } for(int i = 1; i <= n; i ++){ for(int j = 2; j <= m; j ++){ if(str[i][j - 1] == 'X') G[1][i][j] = G[1][i][j - 1]; else G[1][i][j] = j - 1; } } for(int i = 1; i <= n; i ++){ for(int j = m - 1; j >= 1 ; j --){ if(str[i][j + 1] == 'X') G[2][i][j] = G[2][i][j + 1]; else G[2][i][j] = j + 1; } } for(int i = 2; i <= n; i ++){ for(int j = 1; j <= m; j ++){ if(str[i - 1][j] == 'X') G[3][i][j] = G[3][i - 1][j]; else G[3][i][j] = i - 1; } } bfs(); if(dis[ex][ey] == 0) printf("-1\n"); else { printf("%d\n",dis[ex][ey] - 1); string s; char d[4] = {'D', 'L', 'R', 'U'}; while(ex!=sx || ey!=sy){ s += d[dir[ex][ey]]; int x = path[ex][ey].first; int y = path[ex][ey].second; ex = x; ey = y; } reverse(s.begin(), s.end()); printf("%s\n", s.c_str()); } } /* 3 1 2 3 2 2 6 */
链接:http://poj.org/problem?id=2528
都是值得离散化在处理,确实也是要离散化在处理,但是没有那么简单;
1
2
1 3
5 7
这组样例,杀很多离散化处理代码了。
所以我们对每个出现过的数字,还要把他们+1的数保存下来,在离散化处理;
#include"stdio.h" #include"string.h" #include"stack" #include"map" #include"math.h" #include"iostream" #include"vector" #include"queue" #include"set" #include"algorithm" using namespace std; #define OK printf("\n"); #define Debug printf("this_ok\n"); #define inf 1e9 #define INF 1e18 typedef long long ll; #define scanll(a,b) scanf("%lld%lld",&a,&b); #define scanl(a) scanf("%lld",&a); #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld\n",a); #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d\n",a); typedef pair<int,int> PII; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } const ll mod = 998244353; const int N = 300100; int n,a[N],b[N],op[N][2],top,len; int root,lc[N << 4],rc[N << 4],tot,val[N << 4],laze[N << 4]; void push_down(int rt){ if(laze[rt] == 0) { return ; } val[lc[rt]] = val[rc[rt]] = laze[rt]; laze[lc[rt]] = laze[rc[rt]] = laze[rt]; laze[rt] = 0; } void Build_Tree(int &rt,int l,int r){ rt = ++ tot; val[rt] = 0; laze[rt] = 0; if(l == r) return ; int mid = (l + r) >> 1; Build_Tree(lc[rt],l,mid); Build_Tree(rc[rt],mid + 1,r); } void Update(int rt,int L,int R,int l,int r,int color){ if(l <= L && r >= R){ laze[rt] = color; val[rt] = color; return ; } push_down(rt); int mid = (L + R) >> 1; if(l <= mid) Update(lc[rt],L,mid,l,r,color); if(r > mid) Update(rc[rt],mid + 1,R,l,r,color); } int query(int rt,int L,int R,int pos){ if(L == R) return val[rt]; int mid = (L + R) >> 1; push_down(rt); if(pos <= mid) return query(lc[rt],L,mid,pos); else return query(rc[rt],mid + 1,R,pos); } int main(){ int T = read(); while(T --){ n = read(); set<int> Q; tot = 0; top = 0; for(int i = 1; i <= n; i ++){ op[i][0] = read(); op[i][1] = read(); a[++ top] = op[i][0]; b[top] = a[top]; a[++ top] = op[i][1]; b[top] = a[top]; a[++ top] = op[i][0] + 1; b[top] = a[top]; a[++ top] = op[i][1] + 1; b[top] = a[top]; } sort(b + 1,b + top + 1); len = unique(b + 1,b + top + 1) - b - 1; Build_Tree(root,1,len); for(int i = 1;i <= n; i ++){ int l = lower_bound(b + 1,b + len + 1,op[i][0]) - b; int r = lower_bound(b + 1,b + len + 1,op[i][1]) - b; Update(root,1,len,l,r,i); } int ans = 0; // printf("%d\n",len); for(int i = 1;i <= len; i ++){ int x = query(root,1,len,i); // printf("x = %d b[i] = %d\n",x,b[i]); if(x >= 1 && x <= n) Q.insert(x); } printf("%d\n",Q.size()); } } /* 3 1 2 3 2 2 6 */
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6430
这个题有点东西。我们发现1-100000中的因子数量只有200多。所以我们对每个点都建立一个1-100000的权值线段树,同时从叶子结点向上进行合并。
在合并的过程中,不断的更新答案。
#include <iostream> #include <string> #include <cstring> #include <algorithm> #include <cstdio> #include <cctype> #include <queue> #include <stdlib.h> #include <cstdlib> #include <math.h> #include <set> #include <vector> #define inf 107374182 #define M 10010001 #define ll int #define PII pair<int,int> using namespace std; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } const int N = 200200; int n,a[N]; int head[N],ver[N * 400],Next[N * 400],tot,ans[N]; vector<int>F[N]; int maxx; int root[N],lson[N * 400],rson[N * 400],val[N * 400],top; void add(int x,int y){ ver[++ tot] = y; Next[tot] = head[x]; head[x] = tot; } void init(){ for(int i = 1; i <= 100100; i ++){ for(int j = i; j <= 100100; j += i) F[j].push_back(i); } } void Update(int &rt,int l,int r,int x){ if(rt == 0) rt = ++ top; if(l == r) {val[rt] = x;return ;} int mid = (l + r) >> 1; if(x <= mid) Update(lson[rt],l,mid,x); else Update(rson[rt],mid + 1,r,x); val[rt] = max(val[lson[rt]],val[rson[rt]]); } int Merge(int rtx,int rty,int l,int r,int u){ if(!rtx || !rty) return rtx | rty; if(val[rtx] == val[rty]) ans[u] = max(ans[u],val[rtx]); int mid = (l + r) >> 1; lson[rtx] = Merge(lson[rtx],lson[rty],l,mid,u); rson[rtx] = Merge(rson[rtx],rson[rty],mid + 1,r,u); return rtx; } void dfs(int x){ for(int i = 0; i < F[a[x]].size(); i ++){ Update(root[x],1,maxx,F[a[x]][i]); } for(int i = head[x]; i; i = Next[i]){ int y = ver[i]; dfs(y); root[x] = Merge(root[x],root[y],1,maxx,x); } } int main(){ n = read(); init(); val[0] = 0; for(int i = 2; i <= n; i ++){ int x = read(); add(x,i); } for(int i = 1; i <= n; i ++) {a[i] = read();ans[i] = -1; maxx = max(maxx,a[i]); } maxx ++; dfs(1); for(int i = 1; i <= n; i++){ printf("%d\n",ans[i]); } }
链接:https://codeforces.ml/contest/1407/problem/D
手动模拟一下就能发现这就是两个单调栈;单调栈+dp
然后不断更新值;
#include<iostream> #include<cstdio> #include"stack" #include<cstring> #include<algorithm> #include<queue> using namespace std; #define inf 1e9+7 inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); } return s * w; } const int N = 300100, M = 200010; int n,a[N]; int dp[N]; stack<int> Q1,Q2; int L1[N],L2[N]; int main() { n = read(); dp[1] = 0; for(int i = 1; i <= n; i ++) {a[i] = read();if(i != 1)dp[i] = dp[i - 1] + 1;} for(int i = 1; i <= n; i ++){ if(i == 1){ Q1.push(i); Q2.push(i); continue; } while(!Q1.empty() && a[i] > a[Q1.top()]){ // if(a[i] != a[Q1.top()]) dp[i] = min(dp[i],dp[Q1.top()] + 1); Q1.pop(); } if(Q1.size()){ dp[i] = min(dp[i],dp[Q1.top()] + 1); if(a[Q1.top()] == a[i]) Q1.pop(); } Q1.push(i); while(!Q2.empty() && a[i] < a[Q2.top()]){ // if(a[i] != a[Q2.top()]) dp[i] = min(dp[i],dp[Q2.top()] + 1); Q2.pop(); } if(Q2.size()){ dp[i] = min(dp[i],dp[Q2.top()] + 1); if(a[Q2.top()] == a[i]) Q2.pop(); } Q2.push(i); } printf("%d\n",dp[n]); }