2018 ACM-ICPC World Finals

我重写行不?

Comma Sprinkler

签到题,类似于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 }
Aguin

Wireless is the New Fiber

题意是构造一棵树使得树上度与原图度不相等的节点尽量少。

考虑一个贪心,按度从小到大排序后,对于每个度大于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
%d %d
", ans1, n, int(ans2.size()));
54     for(int i = 0; i < ans2.size(); ++i) printf("%d %d
", ans2[i].first - 1, ans2[i].second - 1);
55     return 0;
56 }
Aguin

Go with the Flow

暴力枚举长度,然后算每个空格的最长链,时限卡的有点紧。

 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
", wid, ans);
51     return 0;
52 }
Aguin

Catch the Plane

将线路按出发时间排序,倒着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
", (*f[0].begin()).second);
35     return 0;
36 }
Aguin

Single Cut of Failure

注意到取两条对角线是一定可以切到所有线段的,因此答案最大为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
%.8f %.8f %.8f %.8f
", ax1, ay1, ax2, ay2);
41             one = 1; break;
42         }
43         vis[v[i].second] = false, --cnt;
44     }
45     if(!one) printf("2
0.5 0 %.8f %.8f
0 %.8f %.8f %.8f
", w - 0.5, 1.0 * h, h - 0.5, 1.0 * w, 0.5);
46     return 0;
47 }
Aguin

Triangles

考虑统计每个▽,将图上下翻转后再做一次即为全部三角形。

按从右往左从上往下的顺序扫描每一个方向斜线上的点,考虑这个点作为▽下顶点的贡献。

假设这个点往左上,右上延伸的最大长度分别为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 }
Aguin

Panda Preserve

由于圆半径一致,对于多边形内的每一个点,总是最先被距离自己最近的顶点覆盖到。

也即是说,每个顶点要覆盖到以自己为最近顶点的区域,即维诺图,又称泰森多边形,只要枚举顶点做中垂线即可得到这个凸多边形。

我们只关心这个凸多边形和原多边形交的部分,关键点只有两种情况:凸多边形顶点在原多边形内部;两多边形交点。

暴力求出关键点算距离取最大值即可。

需要抄的板子大概是一个中垂线,半平面交,点多边形位置关系。

  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
", ans);
124     return 0;
125 }
Aguin

Gem Island

考虑分批发放,每次给选中的人一批人各发一个宝石,例如第一步可以看成是给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
", ans / c[d + n - 1][d]);
31     return 0;
32 }
Aguin

Getting a Jump on Crime

枚举格子对判断是否可达,先根据距离和高度差可以求出运动时间,注意判无解的情况,然后可以得到轨迹方程。

然后算这条轨迹在水平面投影的直线,计算投影和每条横线、纵线的交点位置,如果不在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 ? '
' : ' ');
137         }
138     }
139     return 0;
140 }
Aguin

最后两题不看了西西

原文地址:https://www.cnblogs.com/Aguin/p/8883601.html