我重写行不?
签到题,类似于BFS用两个队列维护每种单词前/后是否有逗号向前/后扩展,需要注意如果有句号挡着是不能扩展过去的,不过样例有。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e6 + 10; 4 map<string, vector<int>> M; 5 bool pre[maxn], suc[maxn]; 6 bool st[maxn], ed[maxn]; 7 queue<string> QP, QS; 8 set<string> SP, SS; 9 string str[maxn]; 10 11 int main() { 12 string s; 13 getline(cin, s); 14 int l = s.length(), p = 1; 15 st[p] = true; 16 for(int i = 0; i < l; ++i) { 17 if(s[i] == ',') { 18 suc[p] = pre[p + 1] = true; 19 ++p, ++i; 20 } 21 else if(s[i] == '.') { 22 ed[p] = st[p + 1] = true; 23 ++p, ++i; 24 } 25 else if(s[i] == ' ') ++p; 26 else str[p].push_back(s[i]); 27 } 28 for(int i = 1; i < p; ++i) M[str[i]].push_back(i); 29 for(int i = 1; i < p; ++i) { 30 if(pre[i] && SP.find(str[i]) == SP.end()) SP.insert(str[i]), QP.push(str[i]); 31 if(suc[i] && SS.find(str[i]) == SS.end()) SS.insert(str[i]), QS.push(str[i]); 32 } 33 while(!QP.empty() || !QS.empty()) { 34 while(!QP.empty()) { 35 string cur = QP.front(); QP.pop(); 36 vector<int>& pos = M[cur]; 37 for(int i = 0; i < pos.size(); ++i) { 38 int x = pos[i]; 39 if(!st[x]) pre[x] = true; 40 if(x - 1 > 0 && !ed[x - 1] && SS.find(str[x - 1]) == SS.end()) suc[x - 1] = true, SS.insert(str[x - 1]), QS.push(str[x - 1]); 41 } 42 } 43 while(!QS.empty()) { 44 string cur = QS.front(); QS.pop(); 45 vector<int>& pos = M[cur]; 46 for(int i = 0; i < pos.size(); ++i) { 47 int x = pos[i]; 48 if(!ed[x]) suc[x] = true; 49 if(x + 1 < p && !st[x + 1] && SP.find(str[x + 1]) == SP.end()) pre[x + 1] = true, SP.insert(str[x + 1]), QP.push(str[x + 1]); 50 } 51 } 52 } 53 for(int i = 1; i < p; ++i) { 54 cout << str[i]; 55 if(ed[i]) cout << '.'; 56 else if(suc[i]) cout << ','; 57 if(i < p - 1) cout << ' '; 58 else cout << endl; 59 } 60 return 0; 61 }
题意是构造一棵树使得树上度与原图度不相等的节点尽量少。
考虑一个贪心,按度从小到大排序后,对于每个度大于1的点,在上面挂叶子直到度为1,那么这个连通块也看成一个叶子。
如果某个时刻叶子不够了,那么就舍弃度最大的点,把它当做叶子挂上去。
最后如果还有叶子没用完,若剩两个叶子正好拼成一棵树,否则舍弃一个叶子作为根把别的挂上去。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e4 + 10; 4 typedef pair<int, int> pii; 5 int deg[maxn], id[maxn]; 6 vector<pii> ans2; 7 vector<int> one; 8 9 bool cmp(int i, int j) { 10 return deg[i] < deg[j]; 11 } 12 13 int main() { 14 int n, m; 15 scanf("%d %d", &n, &m); 16 int ans1 = n; 17 for(int i = 1; i <= m; ++i) { 18 int u, v; 19 scanf("%d %d", &u, &v); 20 ++u, ++v; 21 deg[u] += 1, deg[v] += 1; 22 } 23 for(int i = 1; i <= n; ++i) id[i] = i; 24 sort(id + 1, id + 1 + n, cmp); 25 int st = 1, ed = n; 26 while(st <= n && deg[id[st]] == 1) { 27 one.push_back(id[st]); 28 ++st; 29 } 30 for(int i = st; i <= ed; ++i) { 31 int x = id[i]; 32 while(deg[x] > 1 && !one.empty()) { 33 int y = one.back(); 34 one.pop_back(); 35 deg[x]--, deg[y]--; 36 ans1--; 37 ans2.emplace_back(pii(x, y)); 38 } 39 while(deg[x] > 1 && ed > i) { 40 int y = id[ed]; 41 deg[x]--, deg[y]--; 42 ans2.emplace_back(pii(x, y)); 43 ed--; 44 } 45 if(deg[x] == 1) one.push_back(x); 46 } 47 if(one.size() > 1) { 48 for(int i = 1; i < one.size(); ++i) 49 ans2.emplace_back(pii(one[0], one[i])); 50 ans1 -= one.size() - 1; 51 if(one.size() == 2) ans1--; 52 } 53 printf("%d\n%d %d\n", ans1, n, int(ans2.size())); 54 for(int i = 0; i < ans2.size(); ++i) printf("%d %d\n", ans2[i].first - 1, ans2[i].second - 1); 55 return 0; 56 }
暴力枚举长度,然后算每个空格的最长链,时限卡的有点紧。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 3e5 + 10; 4 int pre[maxn], cur[maxn]; 5 vector<int> v; 6 7 int main() { 8 int n, wid = -1, ans = 0, sum = 0, M = 0; 9 scanf("%d", &n); 10 for(int i = 1; i <= n; ++i) { 11 char s[111]; 12 scanf("%s", s); 13 int l = strlen(s); 14 v.push_back(l); 15 M = max(M, l); 16 sum += l; 17 } 18 for(int W = M; W <= sum + n - 1; ++W) { 19 int tmp = 0; 20 vector<int> P, C; 21 int pos = 0, fir = 1, ok = 0; 22 for(int i = 0; i < v.size(); ++i) { 23 if(!fir && pos + 1 + v[i] > W) { 24 for(int j = 0; j < P.size(); ++j) pre[P[j]] = 0; 25 for(int j = 0; j < C.size(); ++j) pre[C[j]] = cur[C[j]], cur[C[j]] = 0; 26 P = C, C.clear(); 27 fir = 1; 28 pos = 0; 29 } 30 if(fir) { 31 pos += v[i]; 32 fir = 0; 33 } 34 else { 35 pos += 1; 36 int r = 1; 37 if(pos > 1) r = max(r, pre[pos - 1] + 1); 38 r = max(r, pre[pos] + 1); 39 if(pos < W) r = max(r, pre[pos + 1] + 1); 40 cur[pos] = r, C.push_back(pos); 41 pos += v[i]; 42 tmp = max(tmp, r); 43 } 44 if(pos == W) ok = 1; 45 } 46 if(ok && tmp > ans) ans = tmp, wid = W; 47 for(int j = 0; j < P.size(); ++j) pre[P[j]] = 0; 48 for(int j = 0; j < C.size(); ++j) cur[C[j]] = 0; 49 } 50 printf("%d %d\n", wid, ans); 51 return 0; 52 }
将线路按出发时间排序,倒着dp。
对于每条线路(a, b, s, t, p),记a点在严格大于s时刻的最优值为ta,b点在严格大于t的最优值为tb。
每个时刻的决策有两种,若选择乘坐,则以p的概率转移到tb,1 - p概率继承ta;若不乘坐则直接继承ta。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef pair<ll, int> pr; 5 const int maxn = 1e6 + 10; 6 map<ll, double> :: iterator ita, itb; 7 map<ll, double> f[maxn]; 8 int a[maxn], b[maxn]; 9 ll s[maxn], t[maxn]; 10 double p[maxn]; 11 vector<pr> v; 12 13 int main() { 14 ll k; 15 int m, n; 16 scanf("%d %d %lld", &m, &n, &k); 17 for(int i = 1; i <= m; ++i) { 18 scanf("%d %d %lld %lld %lf", a + i, b + i, s + i, t + i, p + i); 19 v.emplace_back(pr(s[i], i)); 20 } 21 sort(v.begin(), v.end()); 22 f[1][k + 1] = 1; 23 for(int i = int(v.size()) - 1; i >= 0; --i) { 24 int e = v[i].second, ai = a[e], bi = b[e]; 25 ll si = v[i].first, ti = t[e]; 26 double pi = p[e]; 27 ita = f[ai].upper_bound(si); 28 itb = f[bi].upper_bound(ti); 29 double ta = 0, tb = 0; 30 if(ita != f[ai].end()) ta = (*ita).second; 31 if(itb != f[bi].end()) tb = (*itb).second; 32 f[ai][si] = max(f[ai][si], max(ta, pi * tb + (1 - pi) * ta)); 33 } 34 printf("%.8f\n", (*f[0].begin()).second); 35 return 0; 36 }
注意到取两条对角线是一定可以切到所有线段的,因此答案最大为2,只需考虑1的情况。
将线段转变为环上的区间,相当于找两个端点切开所有区间。
枚举其中一个位置,另一个双指针单调移动。
最后将答案投回矩形上的位置。
注意不能重点,不能取角点。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e6 + 10; 4 typedef pair<int, int> pii; 5 bool vis[maxn]; 6 vector<pii> v; 7 int n, w, h; 8 9 inline int cal(int x, int y) { 10 if(x == 0) return y; 11 if(y == h) return h + x; 12 if(x == w) return 2 * h + w - y; 13 return 2 * (h + w) - x; 14 } 15 16 inline void get(double t, double& x, double& y) { 17 if(t <= h) x = 0, y = t; 18 else if(t <= h + w) x = t - h, y = h; 19 else if(t <= 2 * h + w) x = w, y = 2 * h + w - t; 20 else x = 2 * (h + w) - t, y = 0; 21 } 22 23 int main() { 24 scanf("%d %d %d", &n, &w, &h); 25 for(int i = 0; i < n; ++i) { 26 int X1, Y1, X2, Y2; 27 scanf("%d %d %d %d", &X1, &Y1, &X2, &Y2); 28 v.push_back(pii(cal(X1, Y1), i)); 29 v.push_back(pii(cal(X2, Y2), i)); 30 } 31 sort(v.begin(), v.end()); 32 int sz = int(v.size()), p = 0, cnt = 0, one = 0; 33 for(int i = 0; i < sz; ++i) { 34 if(p == i) vis[v[i].second] = true, ++p, ++cnt; 35 while(!vis[v[p].second]) vis[v[p].second] = true, p = (p + 1) % sz, ++cnt; 36 if(cnt == n) { 37 double ax1, ay1, ax2, ay2; 38 get(v[i].first - 0.5, ax1, ay1); 39 get(v[p].first - 0.5, ax2, ay2); 40 printf("1\n%.8f %.8f %.8f %.8f\n", ax1, ay1, ax2, ay2); 41 one = 1; break; 42 } 43 vis[v[i].second] = false, --cnt; 44 } 45 if(!one) printf("2\n0.5 0 %.8f %.8f\n0 %.8f %.8f %.8f\n", w - 0.5, 1.0 * h, h - 0.5, 1.0 * w, 0.5); 46 return 0; 47 }
考虑统计每个▽,将图上下翻转后再做一次即为全部三角形。
按从右往左从上往下的顺序扫描每一个\方向斜线上的点,考虑这个点作为▽下顶点的贡献。
假设这个点往左上,右上延伸的最大长度分别为UL和UR,那么相当于询问在向上min(UL, UR)的范围内有多少横线长度大于等于到枚举顶点的距离。
这个直观感觉不太好统计,那么反过来考虑每一条横线对于哪些▽下顶点是有效的。
假设在某点处向右的最大距离为R,那么这条横线对于它下方R范围内的顶点都是可以作为三角形▽上边的。
在扫描的过程中顺便维护好UL,UR和R,用一个树状数组维护这个\斜线上横线的贡献,即在扫描到的时候+1,在下方R处加一个删除标记,扫到的时候删掉。
枚举下顶点的时候,只要在树状数组上询问一下min(UL, UR)范围内的有效横线数目。
时限很紧,不仅要比较好的读入还要常数小。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 int f[66666]; 6 inline int lowbit(int s) { 7 return s & (-s); 8 } 9 inline void modify(int i, int x, int n) { 10 while (i <= n) f[i] += x, i += lowbit(i); 11 } 12 inline int query(int i) { 13 int ret = 0; 14 while (i > 0) ret += f[i], i -= lowbit(i); 15 return ret; 16 } 17 vector<int> del[66666]; 18 19 int main() { 20 ios_base :: sync_with_stdio(0); 21 cin.tie(0); 22 int r, c; 23 cin >> r >> c; 24 r = 2 * r - 1, c = 2 * c - 1; 25 vector<string> s(r); 26 getline(cin, s[0]); 27 for(int i = 0; i < r; ++i) { 28 getline(cin, s[i]); 29 while(s[i].length() < c) s[i].push_back(' '); 30 } 31 ll ans = 0; 32 for(int rot = 0; rot < 2; ++rot) { 33 vector< vector<int> > R(r, vector<int>(c, 0)); 34 vector< vector<int> > UL(r, vector<int>(c, 0)); 35 vector< vector<int> > UR(r, vector<int>(c, 0)); 36 for(int j = c - 1; j >= 0; --j) { 37 if(s[0][j] != 'x') continue; 38 int maxi = min((r - 1) / 2, (c - 1 - j) / 2) + 1; 39 for(int ii = 0, jj = j; ii < r && jj < c; ii += 2, jj += 2) { 40 if(jj + 2 < c && s[ii][jj + 2] != ' ') R[ii][jj] = R[ii][jj + 4] + 1; 41 if(ii >= 2 && jj >= 2 && s[ii - 1][jj - 1] != ' ') UL[ii][jj] = UL[ii - 2][jj - 2] + 1; 42 if(ii >= 2 && jj + 2 < c && s[ii - 1][jj + 1] != ' ') UR[ii][jj] = UR[ii - 2][jj + 2] + 1; 43 ans += query(ii / 2 + 1) - query(ii / 2 - min(UL[ii][jj], UR[ii][jj])); 44 if(R[ii][jj]) { 45 modify(ii / 2 + 1, 1, maxi); 46 del[min(ii / 2 + 1 + R[ii][jj], maxi)].push_back(ii / 2 + 1); 47 } 48 for(auto x: del[ii / 2 + 1]) modify(x, -1, maxi); 49 del[ii / 2 + 1].clear(); 50 } 51 } 52 for(int i = 1; i < r; i++) { 53 if(s[i][0] != 'x') continue; 54 int maxj = min((r - 1 - i) / 2, (c - 1) / 2) + 1; 55 for(int ii = i, jj = 0; ii < r && jj < c; ii += 2, jj += 2) { 56 if(jj + 2 < c && s[ii][jj + 2] != ' ') R[ii][jj] = R[ii][jj + 4] + 1; 57 if(ii >= 2 && jj >= 2 && s[ii - 1][jj - 1] != ' ') UL[ii][jj] = UL[ii - 2][jj - 2] + 1; 58 if(ii >= 2 && jj + 2 < c && s[ii - 1][jj + 1] != ' ') UR[ii][jj] = UR[ii - 2][jj + 2] + 1; 59 ans += query(jj / 2 + 1) - query(jj / 2 - min(UL[ii][jj], UR[ii][jj])); 60 if(R[ii][jj]) { 61 modify(jj / 2 + 1, 1, maxj); 62 del[min(jj / 2 + 1 + R[ii][jj], maxj)].push_back(jj / 2 + 1); 63 } 64 for(auto x: del[jj / 2 + 1]) modify(x, -1, maxj); 65 del[jj / 2 + 1].clear(); 66 } 67 } 68 reverse(s.begin(), s.end()); 69 } 70 cout << ans << endl; 71 return 0; 72 }
由于圆半径一致,对于多边形内的每一个点,总是最先被距离自己最近的顶点覆盖到。
也即是说,每个顶点要覆盖到以自己为最近顶点的区域,即维诺图,又称泰森多边形,只要枚举顶点做中垂线即可得到这个凸多边形。
我们只关心这个凸多边形和原多边形交的部分,关键点只有两种情况:凸多边形顶点在原多边形内部;两多边形交点。
暴力求出关键点算距离取最大值即可。
需要抄的板子大概是一个中垂线,半平面交,点多边形位置关系。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef double db; 5 const db eps=1e-6; 6 int sign(db k){ 7 if (k>eps) return 1; else if (k<-eps) return -1; return 0; 8 } 9 int cmp(db k1,db k2){return sign(k1-k2);} 10 int inmid(db k1,db k2,db k3){return sign(k1-k3)*sign(k2-k3)<=0;}// k3 在 [k1,k2] 内 11 struct point{ 12 db x,y; 13 point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};} 14 point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};} 15 point operator * (db k1) const{return (point){x*k1,y*k1};} 16 point operator / (db k1) const{return (point){x/k1,y/k1};} 17 int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;} 18 // 逆时针旋转 19 point turn90(){return (point){-y,x};} 20 bool operator < (const point k1) const{ 21 int a=cmp(x,k1.x); 22 if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1; 23 } 24 db abs(){return sqrt(x*x+y*y);} 25 int getP() const{return sign(y)==1||(sign(y)==0&&sign(x)==-1);} 26 }; 27 int inmid(point k1,point k2,point k3){return inmid(k1.x,k2.x,k3.x)&&inmid(k1.y,k2.y,k3.y);} 28 db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;} 29 db dot(point k1,point k2){return k1.x*k2.x+k1.y*k2.y;} 30 // -pi -> pi 31 int compareangle (point k1,point k2){ 32 return k1.getP()<k2.getP()||(k1.getP()==k2.getP()&&sign(cross(k1,k2))>0); 33 } 34 point getLL(point k1,point k2,point k3,point k4){ 35 db w1=cross(k1-k3,k4-k3),w2=cross(k4-k3,k2-k3); return (k1*w2+k2*w1)/(w1+w2); 36 } 37 int intersect(db l1,db r1,db l2,db r2){ 38 if (l1>r1) swap(l1,r1); if (l2>r2) swap(l2,r2); return cmp(r1,l2)!=-1&&cmp(r2,l1)!=-1; 39 } 40 int checkSS(point k1,point k2,point k3,point k4){ 41 return intersect(k1.x,k2.x,k3.x,k4.x)&&intersect(k1.y,k2.y,k3.y,k4.y)&& 42 sign(cross(k3-k1,k4-k1))*sign(cross(k3-k2,k4-k2))<=0&& 43 sign(cross(k1-k3,k2-k3))*sign(cross(k1-k4,k2-k4))<=0; 44 } 45 int onS(point k1,point k2,point q){return inmid(k1,k2,q)&&sign(cross(k1-q,k2-k1))==0;} 46 struct line{ 47 // p[0]->p[1] 48 point p[2]; 49 line(point k1,point k2){p[0]=k1; p[1]=k2;} 50 point& operator [] (int k){return p[k];} 51 int include(point k){return sign(cross(p[1]-p[0],k-p[0]))>0;} 52 point dir(){return p[1]-p[0];} 53 }; 54 point getLL(line k1,line k2){return getLL(k1[0],k1[1],k2[0],k2[1]);} 55 int parallel(line k1,line k2){return sign(cross(k1.dir(),k2.dir()))==0;} 56 int sameDir(line k1,line k2){return parallel(k1,k2)&&sign(dot(k1.dir(),k2.dir()))==1;} 57 int operator < (line k1,line k2){ 58 if (sameDir(k1,k2)) return k2.include(k1[0]); 59 return compareangle(k1.dir(),k2.dir()); 60 } 61 int checkpos(line k1,line k2,line k3){return k3.include(getLL(k1,k2));} 62 vector<line> getHL(vector<line> &L){ // 求半平面交 , 半平面是逆时针方向 , 输出按照逆时针 63 sort(L.begin(),L.end()); deque<line> q; 64 for (int i=0;i<(int)L.size();i++){ 65 if (i&&sameDir(L[i],L[i-1])) continue; 66 while (q.size()>1&&!checkpos(q[q.size()-2],q[q.size()-1],L[i])) q.pop_back(); 67 while (q.size()>1&&!checkpos(q[1],q[0],L[i])) q.pop_front(); 68 q.push_back(L[i]); 69 } 70 while (q.size()>2&&!checkpos(q[q.size()-2],q[q.size()-1],q[0])) q.pop_back(); 71 while (q.size()>2&&!checkpos(q[1],q[0],q[q.size()-1])) q.pop_front(); 72 vector<line>ans; for (int i=0;i<q.size();i++) ans.push_back(q[i]); 73 return ans; 74 } 75 int contain(vector<point>A,point q){ // 2 内部 1 边界 0 外部 76 int pd=0; A.push_back(A[0]); 77 for (int i=1;i<A.size();i++){ 78 point u=A[i-1],v=A[i]; 79 if (onS(u,v,q)) return 1; if (cmp(u.y,v.y)>0) swap(u,v); 80 if (cmp(u.y,q.y)>=0||cmp(v.y,q.y)<0) continue; 81 if (sign(cross(u-v,q-v))<0) pd^=1; 82 } 83 return pd<<1; 84 } 85 86 int main() { 87 int n; 88 double ans = 0; 89 scanf("%d", &n); 90 vector<point> p = vector<point>(n); 91 for(int i = 0; i < n; ++i) scanf("%lf %lf", &p[i].x, &p[i].y); 92 for(int i = 0; i < n; ++i) { 93 vector<line> L; 94 L.emplace_back(line{point{-20000, -20000}, point{20000, -20000}}); 95 L.emplace_back(line{point{20000, -20000}, point{20000, 20000}}); 96 L.emplace_back(line{point{20000, 20000}, point{-20000, 20000}}); 97 L.emplace_back(line{point{-20000, 20000}, point{-20000, -20000}}); 98 for(int j = 0; j < n; ++j) { 99 if(i == j) continue; 100 point mid = (p[i] + p[j]) / 2; 101 L.emplace_back(line{mid, (p[j] - mid).turn90() + mid}); 102 } 103 L = getHL(L); 104 int sz = int(L.size()); 105 if(sz > 2) { 106 vector<point> v = vector<point>(sz); 107 for(int j = 0; j < sz; ++j) { 108 v[j] = getLL(L[j], L[(j + 1) % sz]); 109 if(contain(p, v[j])) ans = max(ans, (p[i] - v[j]).abs()); 110 } 111 for(int j = 0; j < sz; ++j) { 112 line l1 = line{v[j], v[(j + 1) % sz]}; 113 for(int k = 0; k < n; ++k) { 114 line l2 = line{p[k], p[(k + 1) % n]}; 115 if(checkSS(v[j], v[(j + 1) % sz], p[k], p[(k + 1) % n])) { 116 point u = getLL(l1, l2); 117 ans = max(ans, (p[i] - u).abs()); 118 } 119 } 120 } 121 } 122 } 123 printf("%.8f\n", ans); 124 return 0; 125 }
考虑分批发放,每次给选中的人一批人各发一个宝石,例如第一步可以看成是给n个人各发一个宝石,第二步则在n个人中选择一个子集,第三步在第二步选中的人中再选择子集……
用f[i][j][k]表示第i批,已经发了j个宝石,目前选中的人集合大小为k的所有方案前r个人的宝石和,g[i][j][k]表示方案数。
转移考虑枚举k个人的子集l,方案数只要乘上C(k, l),贡献增加是方案数乘min(r, l)。
最后用插板法除个总数就是期望。
第一维空间可以滚动数组,n4敢水敢过。
1 #include <bits/stdc++.h> 2 using namespace std; 3 double c[1005][1005], f[2][505][505], g[2][505][505]; 4 5 int main() { 6 for(int i = 0; i < 1005; ++i) c[i][0] = c[i][i] = 1; 7 for(int i = 2; i < 1005; ++i) 8 for(int j = 1; j < i; ++j) 9 c[i][j] = c[i - 1][j - 1] + c[i - 1][j]; 10 double ans = 0; 11 int n, d, r, o = 0; 12 scanf("%d %d %d", &n, &d, &r); 13 f[0][0][n] = r, g[0][0][n] = 1; 14 for(int i = 2; i <= d + 1; ++i) { 15 o ^= 1; 16 memset(f[o], 0, sizeof(f[o])); 17 memset(g[o], 0, sizeof(g[o])); 18 for(int j = 0; j <= d; ++j) { 19 for(int k = 1; k <= n; ++k) { 20 if(g[o ^ 1][j][k] == 0) continue; 21 for(int l = 1; l <= k; ++l) { 22 if(j + l > d) break; 23 g[o][j + l][l] += g[o ^ 1][j][k] * c[k][l]; 24 f[o][j + l][l] += f[o ^ 1][j][k] * c[k][l] + g[o ^ 1][j][k] * c[k][l] * min(l, r); 25 } 26 } 27 } 28 for(int k = 1; k <= n; ++k) ans += f[o][d][k]; 29 } 30 printf("%.8f\n", ans / c[d + n - 1][d]); 31 return 0; 32 }
枚举格子对判断是否可达,先根据距离和高度差可以求出运动时间,注意判无解的情况,然后可以得到轨迹方程。
然后算这条轨迹在水平面投影的直线,计算投影和每条横线、纵线的交点位置,如果不在4个格子的角落则只要判两边,否则判四周。
最后随便bfs或者floyd一下。
无脑抄板的话只需要一个线段交的样子。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const double g = 9.80665; 4 typedef pair<int, int> pii; 5 vector<pii> G[22][22]; 6 int H[22][22]; 7 8 typedef double db; 9 const db eps=1e-8; 10 int sign(db k){ 11 if (k>eps) return 1; else if (k<-eps) return -1; return 0; 12 } 13 int cmp(db k1,db k2){return sign(k1-k2);} 14 struct point{ 15 db x,y; 16 point operator + (const point &k1) const{return (point){k1.x+x,k1.y+y};} 17 point operator - (const point &k1) const{return (point){x-k1.x,y-k1.y};} 18 point operator * (db k1) const{return (point){x*k1,y*k1};} 19 point operator / (db k1) const{return (point){x/k1,y/k1};} 20 int operator == (const point &k1) const{return cmp(x,k1.x)==0&&cmp(y,k1.y)==0;} 21 bool operator < (const point k1) const{ 22 int a=cmp(x,k1.x); 23 if (a==-1) return 1; else if (a==1) return 0; else return cmp(y,k1.y)==-1; 24 } 25 db abs(){return sqrt(x*x+y*y);} 26 }; 27 db cross(point k1,point k2){return k1.x*k2.y-k1.y*k2.x;} 28 point getLL(point k1,point k2,point k3,point k4){ 29 db w1=cross(k1-k3,k4-k3),w2=cross(k4-k3,k2-k3); return (k1*w2+k2*w1)/(w1+w2); 30 } 31 int intersect(db l1,db r1,db l2,db r2){ 32 if (l1>r1) swap(l1,r1); if (l2>r2) swap(l2,r2); return cmp(r1,l2)!=-1&&cmp(r2,l1)!=-1; 33 } 34 int checkSS(point k1,point k2,point k3,point k4){ 35 return intersect(k1.x,k2.x,k3.x,k4.x)&&intersect(k1.y,k2.y,k3.y,k4.y)&& 36 sign(cross(k3-k1,k4-k1))*sign(cross(k3-k2,k4-k2))<=0&& 37 sign(cross(k1-k3,k2-k3))*sign(cross(k1-k4,k2-k4))<=0; 38 } 39 40 inline double sq(double x) {return x * x;} 41 inline double cal(double a, double b, double c, double x) { 42 return a * x * x + b * x + c; 43 } 44 int ans[22][22]; 45 int main() { 46 int dx, dy, w, v, lx, ly; 47 scanf("%d %d %d %d %d %d", &dx, &dy, &w, &v, &lx, &ly); 48 for(int i = 1; i <= dy; ++i) 49 for(int j = 1; j <= dx; ++j) 50 scanf("%d", &H[i][j]); 51 for(int i = 1; i <= dy; ++i) { 52 for(int j = 1; j <= dx; ++j) { 53 point p1 = point{(i - 0.5) * w, (j - 0.5) * w}; 54 for(int p = 1; p <= dy; ++p) { 55 for(int q = 1; q <= dx; ++q) { 56 if(i == p && j == q) continue; 57 point p2 = point{(p - 0.5) * w, (q - 0.5) * w}; 58 double h = H[p][q] - H[i][j]; 59 double d = (p1 - p2).abs(); 60 if(sq(v) < g * h || sq(g * h - sq(v)) < sq(g) * (sq(d) + sq(h))) continue; 61 double t = sqrt((sq(v) - g * h + sqrt(sq(g * h - sq(v)) - sq(g) * (sq(d) + sq(h)))) / (sq(g) / 2)); 62 double cost = d / t / v; 63 double a = -0.5 * g / sq(v * cost), b = sqrt(1 - sq(cost)) / cost, c = H[i][j]; 64 int ok = 1; 65 for(int o = 1; o < dy; ++o) { 66 point p3 = point{1.0 * w * o, 0.0}; 67 point p4 = point{1.0 * w * o, 1.0 * w * dx}; 68 if(checkSS(p1, p2, p3, p4)) { 69 point its = getLL(p1, p2, p3, p4); 70 double dis = (its - p3).abs() / w; 71 double ht = cal(a, b, c, (its - p1).abs()); 72 if(abs(int(dis) - dis) < eps) { 73 int x1 = int(dis), x2 = x1 + 1; 74 if(ht < H[o][x1] || ht < H[o + 1][x1]) ok = 0; 75 if(ht < H[o][x2] || ht < H[o + 1][x2]) ok = 0; 76 } 77 else if(abs(int(dis) + 1 - dis) < eps) { 78 int x1 = int(dis) + 1, x2 = x1 + 1; 79 if(ht < H[o][x1] || ht < H[o + 1][x1]) ok = 0; 80 if(ht < H[o][x2] || ht < H[o + 1][x2]) ok = 0; 81 } 82 else { 83 int x = int(dis) + 1; 84 if(ht < H[o][x] || ht < H[o + 1][x]) ok = 0; 85 } 86 } 87 } 88 for(int o = 1; o < dx; ++o) { 89 point p3 = point{0.0, 1.0 * w * o}; 90 point p4 = point{1.0 * w * dy, 1.0 * w * o}; 91 if(checkSS(p1, p2, p3, p4)) { 92 point its = getLL(p1, p2, p3, p4); 93 double dis = (its - p3).abs() / w; 94 double ht = cal(a, b, c, (its - p1).abs()); 95 if(abs(int(dis) - dis) < eps) { 96 int x1 = int(dis), x2 = x1 + 1; 97 if(ht < H[x1][o] || ht < H[x1][o + 1]) ok = 0; 98 if(ht < H[x2][o] || ht < H[x2][o + 1]) ok = 0; 99 } 100 else if(abs(int(dis) + 1 - dis) < eps) { 101 int x1 = int(dis) + 1, x2 = x1 + 1; 102 if(ht < H[x1][o] || ht < H[x1][o + 1]) ok = 0; 103 if(ht < H[x2][o] || ht < H[x2][o + 1]) ok = 0; 104 } 105 else { 106 int x = int(dis) + 1; 107 if(ht < H[x][o] || ht < H[x][o + 1]) ok = 0; 108 } 109 } 110 } 111 if(ok) G[i][j].emplace_back(pii(p, q)); 112 } 113 } 114 } 115 } 116 memset(ans, -1, sizeof(ans)); 117 queue<pii> q; 118 q.push(pii(ly, lx)); 119 ans[ly][lx] = 0; 120 while(!q.empty()) { 121 pii tmp = q.front(); q.pop(); 122 int x = tmp.first, y = tmp.second; 123 for(int i = 0; i < G[x][y].size(); ++i) { 124 pii nxt = G[x][y][i]; 125 int xx = nxt.first, yy = nxt.second; 126 if(ans[xx][yy] == -1) { 127 ans[xx][yy] = ans[x][y] + 1; 128 q.push(nxt); 129 } 130 } 131 } 132 for(int i = 1; i <= dy; ++i) { 133 for(int j = 1; j <= dx; ++j) { 134 if(ans[i][j] == -1) putchar('X'); 135 else printf("%d", ans[i][j]); 136 printf("%c", j == dx ? '\n' : ' '); 137 } 138 } 139 return 0; 140 }
最后两题不看了西西