2013多校训练赛第三场 总结
HDU 4621~4631
今天的多校好变态,是IOI冠军出的题,把我们虐的半死了。
简单讲一下今天的情况,今天就只做了两道水题,算是签了个到,然后就卡1011(HDU 4631)一个下午了。其实感觉今天1009的几何是可以做的,因为我之前也做过类似的题,不过最后还是因为没信心做,所以放弃了。目测是可以用PSLG来做1009的,不过当时计算了一下最坏复杂度,觉得会超时,一直没做。
1011啱看上去是kd树,不过当时搞了好久都还是超时。开始的时候我直接上标准kd树,不带平衡功能的,各种超时。然后我就改成预处理整棵树,然后就用标记法来搞点的插入,理论上平均能达到O(log n)每次操作的,因为树的结点是固定下来的。不过最意想不到的是,这样做的kd树最后还是退化了,随便搞一组case就跑了个本地21s,虽然很多500k的数据还是能12s内出答案的。
然后我就加上更多的标记,原来12s的变成7s了,优化了不少。然后还是被我找到要20s+才能出答案的数据。。。_(:з」∠)_这题就一直卡到最后了。
今天0贡献,代码不用队友的,重写了一遍:
居然用set能过,真是大开眼界了。
1 #include <iostream> 2 #include <set> 3 #include <algorithm> 4 #include <cstring> 5 #include <cstdio> 6 #include <ctime> 7 8 using namespace std; 9 10 typedef long long LL; 11 typedef pair<int, int> PII; 12 template<class T> T sqr(T x) { return x * x;} 13 LL dist(PII a, PII b) { return sqr((LL) a.first - b.first) + sqr((LL) a.second - b.second);} 14 #define ITOR iterator 15 set<PII> pts; 16 17 int main() { 18 int T, n; 19 int ax, bx, cx, ay, by, cy; 20 cin >> T; 21 while (T--) { 22 cin >> n >> ax >> bx >> cx >> ay >> by >> cy; 23 //time_t t1 = clock(); 24 pts.clear(); 25 int x = 0, y = 0; 26 LL sum = 0, mn = 1ll << 62, dis; 27 set<PII>::ITOR si, c; 28 PII cur; 29 for (int i = 0; i < n; i++) { 30 x = ((LL) ax * x + bx) % cx; 31 y = ((LL) ay * y + by) % cy; 32 cur = PII(x, y); 33 if (mn == 0) break; 34 if (pts.find(cur) != pts.end()) { mn = 0; break;} 35 pts.insert(cur); 36 c = si = pts.find(cur); 37 c++; 38 while (c != pts.end()) { 39 dis = dist(cur, *c); 40 mn = min(mn, dis); 41 if (sqr((LL) (*c).first - cur.first) >= mn) break; 42 c++; 43 } 44 c = si; 45 while (true) { 46 if (c == pts.begin()) break; 47 c--; 48 dis = dist(cur, *c); 49 mn = min(mn, dis); 50 if (sqr((LL) (*c).first - cur.first) >= mn) break; 51 } 52 if (i) sum += mn; 53 } 54 cout << sum << endl; 55 //cout << "time " << (double) (clock() - t1) / CLOCKS_PER_SEC << endl; 56 } 57 return 0; 58 }
直接状态压缩然后暴力dp枚举子集,for (int j = i; j; j = (j - 1) & i) ;
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 6 using namespace std; 7 8 const int N = 1 << 16; 9 bool vis[N]; 10 int dp[N], top; 11 char str[22], cur[22]; 12 13 bool check() { 14 int s = 0, t = top; 15 while (s < t) if (cur[s++] != cur[t--]) return false; 16 return true; 17 } 18 19 void dfs(int p, int len, int st) { 20 if (p >= len) { 21 if (check()) vis[st] = true; 22 return ; 23 } 24 cur[++top] = str[p]; 25 dfs(p + 1, len, st | 1 << p); 26 top--; 27 dfs(p + 1, len, st); 28 } 29 30 int DP(int len) { 31 memset(dp, 127, sizeof(dp)); 32 dp[0] = 0; 33 for (int i = 1, e = 1 << len; i < e; i++) { 34 for (int j = i; j; j = (j - 1) & i) { 35 if (vis[j]) dp[i] = min(dp[i ^ j] + 1, dp[i]); 36 } 37 } 38 return dp[(1 << len) - 1]; 39 } 40 41 42 int main() { 43 int T; 44 cin >> T; 45 while (T-- && cin >> str) { 46 memset(vis, 0, sizeof(vis)); 47 top = -1; 48 dfs(0, strlen(str), 0); 49 //for (int i = 0; i < (1 << strlen(str)); i++) cout << i << ' ' << vis[i] << endl; 50 cout << DP(strlen(str)) << endl; 51 } 52 return 0; 53 }
4627 ( The Unsolvable Problem )
分3种情况,一种是奇数的时候,直接分解成n/2和n/2+1相乘即可,偶数有两种,其实就是枚举(n/2-1)和(n/2+1)、(n/2-2)和(n/2+2)两个的gcd。
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 6 using namespace std; 7 8 typedef long long LL; 9 inline LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a;} 10 inline LL lcm(LL a, LL b) { return a / gcd(a, b) * b;} 11 12 int main() { 13 int T; 14 LL n; 15 cin >> T; 16 while (T-- && cin >> n) { 17 if (n & 1) cout << (n >> 1) * ((n >> 1) + 1) << endl; 18 else { 19 LL m = n >> 1, ans = m; 20 for (int i = 1; i <= 2; i++) { 21 if (m - i <= 0) break; 22 ans = max(ans, lcm(m + i, m - i)); 23 } 24 cout << ans << endl; 25 } 26 } 27 return 0; 28 }
总的来说,这次就是被惨虐。一个原因是最近在恶补基础,没有锻炼思维的灵活性,题目稍微变形就只会死板的解题是不行的。在补完基础以后再加强一下!
UPD:
PSLG简单模型。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <ctime> 7 #include <vector> 8 #include <map> 9 #include <set> 10 11 using namespace std; 12 13 const int N = 11111; 14 const double EPS = 1e-8; 15 template<class T> T sqr(T x) { return x * x;} 16 inline int sgn(double x) { return (x > EPS) - (x < -EPS);} 17 struct Point { 18 double x, y; 19 int id; 20 Point() {} 21 Point(double x, double y) : x(x), y(y) {} 22 Point operator + (Point a) { return Point(x + a.x, y + a.y);} 23 Point operator - (Point a) { return Point(x - a.x, y - a.y);} 24 Point operator * (double p) { return Point(x * p, y * p);} 25 Point operator / (double p) { return Point(x / p, y / p);} 26 bool operator < (Point a) const { return sgn(x - a.x) < 0 || sgn(x - a.x) == 0 && y < a.y;} 27 bool operator == (Point a) const { return sgn(x - a.x) == 0 && sgn(y - a.y) == 0;} 28 } ips[N]; 29 30 inline double cross(Point a, Point b) { return a.x * b.y - a.y * b.x;} 31 inline double dot(Point a, Point b) { return a.x * b.x + a.y * b.y;} 32 inline double veclen(Point x) { return sqrt(dot(x, x));} 33 inline Point vecunit(Point x) { return x / veclen(x);} 34 inline Point normal(Point x) { return Point(-x.y, x.x) / veclen(x);} 35 36 struct Line { 37 Point s, t; 38 Line() {} 39 Line(Point s, Point t) : s(s), t(t) {} 40 Point vec() { return t - s;} 41 Point point(double d) { return s + vec() * d;} 42 } ; 43 44 inline Point llint(Line a, Line b) { return a.point(cross(b.vec(), a.s - b.s) / cross(a.vec(), b.vec()));} 45 inline bool onseg(Point x, Point a, Point b) { return sgn(cross(a - x, b - x)) == 0 && sgn(dot(a - x, b - x)) <= 0;} 46 47 int ptinpoly(Point p, Point *pt, int n) { 48 int wn = 0; 49 pt[n] = pt[0]; 50 for (int i = 0; i < n; i++) { 51 if (onseg(p, pt[i], pt[i + 1])) return -1; 52 int k = sgn(cross(pt[i + 1] - pt[i], p - pt[i])); 53 int d1 = sgn(pt[i].y - p.y); 54 int d2 = sgn(pt[i + 1].y - p.y); 55 if (k > 0 && d1 <= 0 && d2 > 0) wn++; 56 if (k < 0 && d2 <= 0 && d1 > 0) wn--; 57 } 58 return wn != 0; 59 } 60 61 Point tri[55][4], pts[222]; 62 typedef pair<double, int> PDI; 63 typedef pair<int, int> PII; 64 vector<PDI> rel[N]; 65 map<int, int> nxp[N]; 66 set<PII> vis; 67 double ans[55]; 68 69 inline double angle(Point x) { return atan2(x.y, x.x);} 70 bool operator < (PDI a, PDI b) { return sgn(a.first - b.first) < 0 || sgn(a.first - b.first) == 0 && a.second < b.second;} 71 bool operator == (PDI a, PDI b) { return sgn(a.first - b.first) == 0 && a.second == b.second;} 72 73 int main() { 74 //freopen("in", "r", stdin); 75 int T, n, m; 76 scanf("%d\n", &T); 77 while (T-- && ~scanf("%d", &n)) { 78 m = 0; 79 for (int i = 0; i < n; i++) { 80 for (int j = 0; j < 3; j++) { 81 scanf("%lf%lf", &tri[i][j].x, &tri[i][j].y); 82 ips[m++] = tri[i][j]; 83 } 84 tri[i][3] = tri[i][0]; 85 } 86 Line a, b; 87 for (int i = 0; i < n; i++) { 88 for (int j = 0; j < 3; j++) { 89 a = Line(tri[i][j], tri[i][j + 1]); 90 for (int x = i + 1; x < n; x++) { 91 if (i == x) continue; 92 for (int y = 0; y < 3; y++) { 93 b = Line(tri[x][y], tri[x][y + 1]); 94 if (sgn(cross(a.vec(), b.vec()))) { 95 ips[m] = llint(a, b); 96 if (onseg(ips[m], a.s, a.t) && onseg(ips[m], b.s, b.t)) m++; 97 } 98 } 99 } 100 } 101 } 102 sort(ips, ips + m); 103 m = (int) (unique(ips, ips + m) - ips); 104 for (int i = 0; i < m; i++) ips[i].id = i, rel[i].clear(), nxp[i].clear(); 105 for (int i = 0; i < n; i++) { 106 for (int j = 0; j < 3; j++) { 107 int t = 0; 108 for (int k = 0; k < m; k++) { 109 if (onseg(ips[k], tri[i][j], tri[i][j + 1])) pts[t++] = ips[k]; 110 } 111 sort(pts, pts + t); 112 for (int i = 1; i < t; i++) { 113 rel[pts[i].id].push_back(PDI(angle(pts[i - 1] - pts[i]), pts[i - 1].id)); 114 rel[pts[i - 1].id].push_back(PDI(angle(pts[i] - pts[i - 1]), pts[i].id)); 115 } 116 } 117 } 118 for (int i = 0; i < m; i++) { 119 sort(rel[i].begin(), rel[i].end()); 120 int t = (int) (unique(rel[i].begin(), rel[i].end()) - rel[i].begin()); 121 while (rel[i].size() > t) rel[i].pop_back(); 122 if (t) { 123 rel[i].push_back(rel[i][0]); 124 for (int j = 0; j < t; j++) nxp[rel[i][j + 1].second][i] = rel[i][j].second; 125 rel[i].pop_back(); 126 } 127 } 128 vis.clear(); 129 memset(ans, 0, sizeof(ans)); 130 Point mid, nor; 131 for (int i = 0, t; i < m; i++) { 132 int sz = rel[i].size(); 133 for (int j = 0; j < sz; j++) { 134 if (vis.find(PII(i, rel[i][j].second)) != vis.end()) continue; 135 double tmp = 0; 136 int c = i, nx = rel[i][j].second; 137 while (vis.find(PII(c, nx)) == vis.end()) { 138 tmp += cross(ips[c], ips[nx]); 139 vis.insert(PII(c, nx)); 140 t = c, c = nx, nx = nxp[t][c]; 141 } 142 c = i, nx = rel[i][j].second; 143 nor = normal(ips[nx] - ips[c]) * 1e-4; 144 mid = (ips[c] + ips[nx]) / 2 + nor; 145 int cnt = 0; 146 for (int i = 0; i < n; i++) { 147 if (ptinpoly(mid, tri[i], 3)) cnt++; 148 } 149 ans[cnt] += tmp; 150 } 151 } 152 for (int i = 1; i <= n; i++) printf("%.6f\n", ans[i] / 2); 153 } 154 return 0; 155 }
——written by Lyon