text-2020
http://acm.hdu.edu.cn/diy/contest_show.php?cid=36899
1010-我!是!签!到!题!:BFS
思路:bfs,普通的用bfs求最短路是先到终点的路径最短,而这里又是最短里面的字典序最小,那么就不能上下左右的顺序任意选择了,而是优先选择小的字母去走,因为D<L<R<U,那么就按照下左右上的顺序去走。
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <queue> #include <string.h> #include <cmath> #include <bitset> #include <set> #include <map> #define ll long long const int inf = 0x3f3f3f3f; const int mod = 1e9+7; const ll ds = 1e15+7; const double p = 3.141592653589793238462643383; using namespace std; struct node{ int x,y,num; string str; node(int a,int b,string s,int n){ x = a; y = b; str = s; num = n; } }; char s[105][105]; char dir[4] = {'D','L','R','U'}; int vis[105][105]; int d[4][2] = {{1,0},{0,-1},{0,1},{-1,0}}; int t,n,m,k,x,y; bool check(int dx,int dy) { if(dx >= 1 && dx <= n && dy >= 1 && dy <= m && !vis[dx][dy] && s[dx][dy] != '#') return true; return false; } void bfs() { queue<node>q; q.push(node(x,y,"",0)); vis[x][y] = 1; while(!q.empty()){ node st = q.front(); q.pop(); int dx,dy; if(s[st.x][st.y] == 'S') { cout << st.num << endl; cout << st.str << endl; break; } for(int i = 0; i < 4; i++){ dx = st.x + d[i][0]; dy = st.y + d[i][1]; if(check(dx,dy)){ vis[dx][dy] = 1; q.push(node(dx,dy,st.str+dir[i],st.num+1)); } } } } int main() { ios::sync_with_stdio(false); cin >> t; while(t--){ cin >> x >> y; cin >> n >> m; memset(vis,0,sizeof(vis)); for(int i = 1; i <= n; i++){ cin >> s[i] + 1; } bfs(); } return 0; }
1001:欧拉函数
思路:根据题意可看出,我们要找出某个最小的数去满足获取全部香蕉,又因为gcd(x,y) != 1的话则咒语失效,所有我们先处理1-1e6中所有数在1-他自己与它互质的数有多少个。
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <queue> #include <string.h> #include <cmath> #include <bitset> #include <set> #include <map> #define ll long long const int inf = 0x3f3f3f3f; const int mod = 1e9+7; const ll ds = 1e15+7; const double p = 3.141592653589793238462643383; using namespace std; //牛牛的算术 int prime[1000005],phi[1000005]; void init() { int cnt = 0; for(int i = 2; i <= 1000000; i++){ if(!phi[i]){ phi[i] = i - 1; prime[cnt++] = i; } for(int j = 0; j < cnt; j++){ if(i * prime[j] > 1000000) break; if(i % prime[j] == 0){ //cout << i * prime[j] << endl; phi[i * prime[j]] = prime[j] * phi[i]; } else phi[i * prime[j]] = phi[prime[j]] * phi[i]; if(i % prime[j] == 0) break; } } } int a[10005]; int main() { ios::sync_with_stdio(false); memset(phi,0,sizeof(phi)); init(); int t,n; cin >> t; while(t--){ cin >> n; ll ans = 0; for(int i = 1; i <= n; i++) cin >> a[i]; for(int i = 1; i <= n; i++){ for(int j = a[i] + 1; j <= 1000000; j++){ if(phi[j] >= a[i]){ ans += 1ll*j; //cout << phi[j] << endl; break; } } } cout << ans << endl; } return 0; }
1002: 二分+单调队列+01分数规划
不能memset(sum,0,sizeof(sum)),否则会超时
思路:
设所选区间为[L,R],那么平均值为:x = (mL+...+mR) / (L-R+1)
即mL-x+m(L+1) - x + ...+ mR - x >= 0
先求出m - x的前缀和,那么[L,R]的和为sum[R] - sum[L-1]
又因为小球个数在[a,b]之间,所有a<= R - L + 1 <= b,又因为实际我们求的是sum[i] - sum[q[pl]]
即a + 1 <= i - q[pl] + 1 <= b + 1
即 去除q[pl] < i - b的那些点。可以使用单调队列求长度在某一区间的最大和。
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <queue> #include <string.h> #include <cmath> #include <bitset> #include <set> #include <map> #define ll long long #define _gcd __gcd const int inf = 0x3f3f3f3f; const int mod = 1e9+7; const ll ds = 1e15+7; const double p = 3.141592653589793238462643383; using namespace std; int mon[100005],n,a,b; double cz[100005],sum[100005]; int q[100005]; //deque<int>q; bool check(double x) { //memset(sum,0,sizeof(sum)); for(int i = 1; i <= n; i++){ cz[i] = (double)mon[i] - x; } sum[0] = 0; for(int i = 1; i <= n; i++){ sum[i] = sum[i - 1] + cz[i]; } int pl = 1,pr = 0; for(int i = 1; i <= n; i++){ if(i >= a){ while(pl <= pr && sum[q[pr]] > sum[i - a]) pr--; pr++; q[pr] = i - a; } while(pl <= pr && q[pl] < i - b) pl++; if(pl <= pr && sum[i] - sum[q[pl]] >= 0) return true; } return false; } int main() { ios::sync_with_stdio(false); while(cin >> n){ cin >> a >> b; for(int i = 1; i <= n; i++) cin >> mon[i]; double l = -10000,r = 10000,ans; ans = l; while(r - l > 1e-5){ double mid = (l + r) / 2; if(check(mid)){ l = mid; ans = mid; } else r = mid; //cout << l << " " << r << endl; } printf("%.3f\n",ans); } return 0; }
双端队列做法:
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <queue> #include <string.h> #include <cmath> #include <bitset> #include <set> #include <map> #define ll long long #define _gcd __gcd const int inf = 0x3f3f3f3f; const int mod = 1e9+7; const ll ds = 1e15+7; const double p = 3.141592653589793238462643383; using namespace std; int mon[100005],n,a,b; double cz[100005],sum[100005]; deque<int>q; bool check(double x) { //memset(sum,0,sizeof(sum)); sum[0] = 0; for(int i = 1; i <= n; i++){ cz[i] = (double)mon[i] - x; } for(int i = 1; i <= n; i++){ sum[i] = sum[i - 1] + cz[i]; } q.clear(); int p = 0; for(int i = a; i <= n; p++,i++){ while(!q.empty() && sum[p] < sum[q.back()]) q.pop_back(); q.push_back(p); while(!q.empty() && (q.front() < i - b)) q.pop_front(); if(sum[i] - sum[q.front()] >= 0) return true; } return false; } int main() { ios::sync_with_stdio(false); while(cin >> n){ cin >> a >> b; for(int i = 1; i <= n; i++) cin >> mon[i]; double l = -10000,r = 10000,ans; ans = l; while(r - l > 1e-5){ double mid = (l + r) / 2; if(check(mid)){ l = mid; ans = mid; } else r = mid; //cout << l << " " << r << endl; } printf("%.3f\n",ans); } return 0; }
1006:dfs序+分块
思路:
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <queue> #include <string.h> #include <cmath> #include <bitset> #include <set> #include <map> #define ll long long const int inf = 0x3f3f3f3f; const int mod = 1e9+7; const ll ds = 1e15+7; const double p = 3.141592653589793238462643383; using namespace std; struct edge{ int v,next; ll val; }edge[400005]; int head[200005],cnt = 0,t,n,y,d,q; int st[200005],en[200005],l[200005],r[200005],belong[200005]; ll len[200005],b[200005]; void init() { for(int i = 0; i <= n; i++) head[i] = -1; } void add(int u,int v,int d) { edge[cnt].v = v; edge[cnt].next = head[u]; edge[cnt].val = 1ll*d; head[u] = cnt++; } void dfs(int s,int f) { t++; st[s] = t; b[t] = len[s]; for(int i = head[s]; ~i; i = edge[i].next){ int v = edge[i].v; if(v == f) continue; len[v] = len[s] + edge[i].val; dfs(v,s); } en[s] = t; } vector<ll>v[200005]; vector<ll>sum[200005]; vector<ll>::iterator it; void build() { b[1] = 0; int block = sqrt(t); int num = t / block; if(t % block) num++; for(int i = 1; i <= num; i++){ l[i] = (i - 1) * block + 1; r[i] = i * block; //v[i].push_back(-1); } r[num] = t; for(int i = 1; i <= t; i++){ belong[i] = (i - 1) / block + 1; v[belong[i]].push_back(b[i]); } for(int i = 1; i <= num; i++){ sort(v[i].begin(),v[i].end()); } ll temp; for(int i = 1; i <= num; i++){ int k = v[i].size(); temp = 0; for(int j = k - 1; j >= 0; j--){ temp += v[i][j]; sum[i].push_back(temp); } } } ll query(int L,int R,ll w,ll k) { ll ans = 0; int bl = belong[L]; int br = belong[R]; if(bl == br){ for(int i = L; i <= R; i++){ if(b[i] - w >= k) ans += b[i] - w; } return ans; } ll temp = k + w; for(int i = L; i <= r[bl]; i++) if(b[i] - w >= k) ans += b[i] - w; for(int i = l[br]; i <= R; i++) if(b[i] - w >= k) ans += b[i] - w; for(int i = bl + 1; i < br; i++){ if(v[i][v[i].size() - 1] < temp) continue; it = lower_bound(v[i].begin(),v[i].end(),temp); int e = v[i].end() - it; if(e == 0) continue; ans += sum[i][e - 1] - w * e; } return ans; } int main() { ios::sync_with_stdio(false); cin >> n; init(); cnt = t = 0; for(int i = 1; i < n; i++){ cin >> y >> d; add(y,i+1,d); add(i+1,y,d); } dfs(1,0); //cout << t << endl; build(); cin >> y; int x; ll k; while(y--){ cin >> x >> k; //cout << st[x] << en[x] << endl; ll ans = query(st[x],en[x],len[x],k); cout << ans << endl; } return 0; }
1009: 最短路
思路:
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <queue> #include <string.h> #include <cmath> #include <bitset> #include <set> #include <map> #define ll long long const int inf = 0x3f3f3f3f; const int mod = 1e9+7; const ll ds = 1e15+7; const double p = 3.141592653589793238462643383; using namespace std; struct Egde{ int v,next; ll val; }edge[2000005]; struct node{ int xb; ll val; node(int a,ll b){ xb = a; val = b; } bool operator < (const node &a)const{ return val > a.val; } }; int head[100005],cnt1,n,m,x; void add(int u,int v,ll val) { edge[cnt1].v = v; edge[cnt1].val = val; edge[cnt1].next = head[u]; head[u] = cnt1++; } void init() { for(int i = 0; i <= n; i++) head[i] = -1; } int vis[100005]; void dij(int st,ll d[]) { for(int i = 0; i <= n; i++) vis[i] = 0,d[i] = ds; priority_queue<node>q; d[st] = 0; q.push(node(st,0)); while(!q.empty()){ node s = q.top(); q.pop(); int t = s.xb; if(vis[t]) continue; vis[t] = 1; for(int i = head[t]; ~i; i = edge[i].next){ int p = edge[i].v; ll sum = edge[i].val; if(vis[p]) continue; if(d[p] > s.val + sum){ d[p] = s.val + sum; q.push(node(p,d[p])); } } } } int main() { int t,u,v,val; ios::sync_with_stdio(false); cin >> t; while(t--){ cnt1 = 0; ll d1[100005]; cin >> n >> m >> x; init(); for(int i = 1; i <= n; i++){ cin >> u; for(int j = 1; j <= u; j++){ cin >> v; if(j == 1) add(i,v,0); else add(i,v,1); } } dij(m,d1); if(d1[x] == ds) cout << -1 << endl; else cout << d1[x] << endl; } return 0; }
1007: 线段树,gcd,更相减损法
思路:
#include <iostream> #include <cstdio> #include <algorithm> #include <stack> #include <queue> #include <string.h> #include <cmath> #include <bitset> #include <set> #include <map> #define ll long long #define _gcd __gcd const int inf = 0x3f3f3f3f; const int mod = 1e9+7; const ll ds = 1e15+7; const double p = 3.141592653589793238462643383; using namespace std; int a[100005],n,m,opt,x,L,R; int tree[400005],s_max[400005],g_max[400005]; void push(int xb) { tree[xb] = tree[xb*2] + tree[xb*2+1]; s_max[xb] = max(s_max[xb*2],s_max[xb*2+1]); g_max[xb] = _gcd(g_max[xb*2],g_max[xb*2+1]); } void build(int l,int r,int xb) { if(l == r) { tree[xb] = a[l]; s_max[xb] = abs(a[l]); g_max[xb] = abs(a[l]); return; } int mid = (l + r) >> 1; build(l,mid,xb*2); build(mid+1,r,xb*2+1); push(xb); } void add(int l,int r,int xb,int k,int val) { if(l == r){ a[l] += val; tree[xb] = a[l]; s_max[xb] = abs(a[l]); g_max[xb] = abs(a[l]); return; } int mid = (l + r) >> 1; if(k <= mid) add(l,mid,xb*2,k,val); else add(mid+1,r,xb*2+1,k,val); push(xb); } int sea_max(int l,int r,int xb,int nl,int nr) { if(nl <= l && nr >= r) return abs(s_max[xb]); int mid = (l + r) >> 1; int l_max = 0,r_max = 0; if(nl <= mid) l_max = sea_max(l,mid,xb*2,nl,nr); if(nr > mid) r_max = sea_max(mid+1,r,xb*2+1,nl,nr); return max(l_max,r_max); } int query(int l,int r,int xb,int nl,int nr) { if(nl <= l && nr >= r) return tree[xb]; int mid = (l + r) >> 1; int ans = 0; if(nl <= mid) ans += query(l,mid,xb*2,nl,nr); if(nr > mid) ans += query(mid+1,r,xb*2+1,nl,nr); return ans; } int sg_max(int l,int r,int xb,int nl,int nr) { if(nl <= l && nr >= r) return g_max[xb]; int mid = (l + r) >> 1; int l_max = 0,r_max = 0; if(nl <= mid) l_max = sg_max(l,mid,xb*2,nl,nr); if(nr > mid) r_max = sg_max(mid+1,r,xb*2+1,nl,nr); return _gcd(l_max,r_max); } int main() { ios::sync_with_stdio(false); int t; while(cin >> t){ while(t--){ memset(tree,0,sizeof(tree)); memset(s_max,0,sizeof(tree)); memset(g_max,0,sizeof(g_max)); cin >> n >> m; a[0] = 0; for(int i = 1; i <= n; i++) cin >> a[i]; for(int i = n; i >= 1; i--) a[i] = a[i] - a[i - 1]; build(1,n,1); while(m--){ cin >> opt >> L >> R; if(opt == 1){ cin >> x; add(1,n,1,L,x); if(R < n) add(1,n,1,R+1,-x); } if(opt == 2){ if(L == R){ cout << 0 << endl; continue; } int ans = sea_max(1,n,1,L + 1,R); cout << ans << endl; } if(opt == 3){ int ans = query(1,n,1,1,L); if(L != R) ans = _gcd(ans,sg_max(1,n,1,L+1,R)); cout << ans << endl; } } } } return 0; }