首页 > 代码库 > SnackDown Online Pre-elimination round A
SnackDown Online Pre-elimination round A
1. 应该n是偶数,就行吧。应该判断1个人,只能出现一次吧。
1 #include<bits/stdc++.h> 2 #define pb push_back 3 typedef long long ll; 4 using namespace std; 5 typedef pair<int, int> pii; 6 const int maxn = 1e3 + 10; 7 8 void yes() {cout << "yes" << endl;} 9 void no() {cout << "no" << endl; }10 int n, c;11 int a[110];12 void solve() {13 memset(a, 0, sizeof a);14 cin >> n >> c;15 int x, y;16 bool tag = 0;17 for (int i = 0; i < c; i++) {18 cin >> x >> y;19 if(a[x] || a[y]) tag = 1;20 a[x] = a[y] = 1;21 }22 if(n % 2 == 1 || tag) no();23 else yes();24 }25 26 int main() {27 // freopen("test.in", "r", stdin);28 //freopen("test.out", "w", stdout);29 ios::sync_with_stdio(0);30 cin.tie(0); cout.tie(0);31 int _;32 cin >> _;33 while(_--)34 solve();35 return 0;36 }
2. 是否是一条蛇,这个浪费了一些时间。
首先#必须组成1个连通分量,多于1个的,肯定是不行的。然后还有其他情况。判断连通分量, dfs或者bfs扫就行。
1个连通分量怎么是一条蛇,我刚开始以为是dfs扫一遍,每一个点的只能有一个前驱和后继,但是这样枚举的复杂度很高,应该会tle。
考虑到只有2行,然后总左到右进行考虑, 每次先考虑上下, 再考虑向右走,然后check,长度是否是#的个数。注意,最左边的点,可能第一个是第一行往下走,或者是第二行往上走,都是可以的。
写的有点丑。
1 #include<bits/stdc++.h> 2 #define pb push_back 3 typedef long long ll; 4 using namespace std; 5 typedef pair<int, int> pii; 6 const int maxn = 1e3 + 10; 7 int n; 8 string s[2]; 9 int c; 10 int cnt; 11 bool vis[2][510]; 12 int dx[] = {0, 0, 1, -1}; 13 int dy[] = {1, -1, 0, 0}; 14 bool check(int x, int y) { 15 if(x >= 0 && x < 2 && y >= 0 && y < n) return 1; 16 return 0; 17 } 18 void dfs(int x, int y) { 19 if(vis[x][y] || s[x][y] == ‘.‘) return; 20 vis[x][y] = 1; 21 cnt++; 22 for (int i = 0; i < 4; i++) { 23 int cx = x + dx[i], cy = y + dy[i]; 24 if(check(cx, cy)) { 25 dfs(cx, cy); 26 } 27 } 28 } 29 void yes() {cout << "yes" << endl; } 30 void no() {cout << "no" << endl; } 31 void solve() { 32 cin >> n; 33 cin >> s[0] >> s[1]; 34 //cout << s[0] << " " << s[1] << endl; 35 c = 0; 36 for (int i = 0; i < n; i++) { 37 if(s[0][i] == ‘#‘) c++; 38 if(s[1][i] == ‘#‘) c++; 39 } 40 int x, y; 41 x = y = -1; 42 for (int j = 0; j < n; j++) { 43 for (int i = 0; i < 2; i++) { 44 if(s[i][j] == ‘#‘) { 45 x = i; y = j; 46 break; 47 } 48 } 49 if(x != -1) break; 50 } 51 cnt = 0; 52 memset(vis, 0, sizeof vis); 53 dfs(x, y); 54 //cout << x << " " << y << endl; 55 //cout << c << " " << cnt << endl; 56 if(cnt != c) { 57 no(); return; 58 } 59 memset(vis, 0, sizeof vis); 60 int dx = x, dy = y; 61 //cout << x << " " << y << endl; 62 while(cnt > 0) { 63 vis[x][y] = 1; 64 cnt--; 65 if(cnt == 0) break; 66 if(s[1 - x][y] == ‘#‘ && !vis[1 - x][y]) { 67 x = 1 - x; 68 } else if(y + 1 < n && s[x][y + 1] == ‘#‘) { 69 y = y + 1; 70 } else { 71 break; 72 73 } 74 } 75 if(cnt == 0) { 76 yes(); return; 77 } 78 cnt = c; 79 //cout << x << " d " << y << endl; 80 x = 1 - dx, y = dy; 81 82 if(s[x][y] != ‘#‘) { 83 no(); return; 84 } 85 memset(vis, 0, sizeof vis); 86 while(cnt > 0) { 87 vis[x][y] = 1; 88 cnt--; 89 if(cnt == 0) break; 90 if(s[1 - x][y] == ‘#‘ && !vis[1 - x][y]) { 91 x = 1 - x; 92 } else if(y + 1 < n && s[x][y + 1] == ‘#‘) { 93 y = y + 1; 94 } else { 95 no(); 96 return; 97 98 } 99 }100 yes();101 }102 103 int main() {104 // freopen("test.in", "r", stdin);105 //freopen("test.out", "w", stdout);106 //ios::sync_with_stdio(0);107 //cin.tie(0); cout.tie(0);108 int _; cin >> _;109 while(_--)110 solve();111 return 0;112 }
3. 这个题目跟资格赛的题目有点像,但是比较难。考虑每个位置的上限是多少,多于这个数,肯定是要必须操作的。
是这样的形式, 1, 2,3 。。。3,2,1, 首先经过这样的缩减。找到必须的操作。 同时又可以观察到,如果第二个数为1, 然后第三个位置的上限就变为2了,而不是3. 这点也很容易想到。每个点只影响左右的点,然后左右的
点,再把这个值传递出去。最后的结果肯定是,没相邻的2个点,最多相差1,而且每个位置的值,都是这个位置可以到达的上限。然后操作,就很简单了,枚举每一个点作为中心, 用所有和减去这个数, 求的最小的需要操作次数,
最后,别忘了加上必须的操作次数。
1 #include<bits/stdc++.h> 2 #define pb push_back 3 typedef long long ll; 4 using namespace std; 5 typedef pair<int, int> pii; 6 const int maxn = 1e5 + 10; 7 8 int n; 9 int a[maxn];10 void solve() {11 scanf("%d", &n);12 ll s = 0;13 for (int i = 1; i <= n; i++) {14 scanf("%d", &a[i]);15 }16 for (int i = 1; i <= n / 2; i++) {17 //cout << i << " " << a[i] << endl;18 //cout << n + 1 - i << " " << a[n + 1 - i] << endl;19 if(a[i] > i) {20 s += a[i] - i;21 a[i] = i;22 }23 if(a[n + 1 - i] > i) {24 s += a[n + 1 - i] - i;25 a[n + 1 - i] = i;26 }27 }28 n++;29 if(n % 2 == 0) {30 if(a[n / 2] > n / 2) {31 s += a[n / 2] - n / 2;32 a[n / 2] = n / 2;33 }34 }35 n--;36 //for (int i = 1; i <= n; i++)37 //cout << i << " ad " << a[i] << endl;38 set<pii> se;39 for (int i = 1; i <= n; i++) {40 se.insert({a[i], i });41 }42 int x, y;43 while(!se.empty()) {44 pii t = *se.begin();45 se.erase(se.begin());46 y = t.first; x = t.second;47 if(x - 1 > 0) {48 if(a[x - 1] > y + 1) {49 se.erase({a[x - 1], x - 1 });50 s += a[x - 1] - y - 1;51 a[x - 1] = y + 1;52 se.insert({a[x - 1], x - 1 });53 }54 }55 if(x + 1 <= n) {56 if(a[x + 1] > y + 1) {57 se.erase({a[x + 1], x + 1 });58 s += a[x + 1] - y - 1;59 a[x + 1] = y + 1;60 se.insert({a[x + 1], x + 1 } );61 }62 }63 }64 //for (int i = 1; i <= n; i++)65 // cout << i << " " << a[i] << endl;66 ll ts = 0;67 for (int i = 1; i <= n; i++)68 ts += a[i];69 ll res = INT_MAX;70 for (int i = 1; i <= n; i++) {71 res = min(res, ts - a[i] * a[i]);72 }73 printf("%lld\n", s + res);74 75 }76 77 int main() {78 //freopen("test.in", "r", stdin);79 //freopen("test.out", "w", stdout);80 int _;81 scanf("%d", &_);82 while(_--)83 solve();84 return 0;85 }
4. 连续的蛇,这个题写出目标方程,很容易简化为就是一个区间求一个点, 使得这些点到目标n个点的差的绝对值和最小。显然是一个二分问题,应该是凹的,但是,是整数上的,所以,用二分很容易做。
1 #include<bits/stdc++.h> 2 #define pb push_back 3 typedef long long ll; 4 using namespace std; 5 typedef pair<int, int> pii; 6 const int maxn = 1e5 + 10; 7 8 int n; 9 ll l, a, b;10 ll s[maxn];11 12 ll work(ll x) {13 ll r = 0;14 for (int i = 0; i < n; i++)15 r += abs(s[i] - x);16 return r;17 }18 void solve() {19 scanf("%d%lld%lld%lld", &n, &l, &a, &b);20 for (int i = 0; i < n; i++) {21 scanf("%lld", &s[i]);22 }23 sort(s, s + n);24 for (int i = 0; i < n; i++)25 s[i] -= i * l;26 //sort(s, s + n);27 ll left = a, right = b - n * l;28 ll ta = left, tb = right;29 while(left < right) {30 ll mid = (left + right) / 2;31 ll x1 = work(mid - 1), x2 = work(mid), x3 = work(mid + 1);32 if(x2 <= x1 && x2 <= x3) {33 left = right = mid;34 } else if(x1 <= x2 && x2 <= x3) {35 right = mid - 1;36 } else {37 left = mid + 1;38 }39 //cout << left << " " << right << endl;;40 }41 if(left < ta) left = ta;42 if(left > tb) left = tb;43 printf("%lld\n", work(left));44 45 }46 47 int main() {48 //freopen("test.in", "r", stdin);49 //freopen("test.out", "w", stdout);50 int t;51 scanf("%d", &t);52 while(t--)53 solve();54 return 0;55 }
5. 保卫毒药,就是一个区间问题,注意到一条蛇,只会贡献水平或者垂直二选一,不能同时贡献。 然后先区分水平和垂直的线段, 然后转化为一维问题, 有一些线段, 求使得覆盖目标区间,最少需要多少线段。这个题目应该是比较
简单的吧,排序,然后遍历一般就可以了。 我手残,居然错了好几次。果然以前想的不明白,写的不熟练。
代码写的很丑的。
1 #include<bits/stdc++.h> 2 #define pb push_back 3 typedef long long ll; 4 using namespace std; 5 typedef pair<int, int> pii; 6 const int maxn = 1e5 + 10; 7 8 int n, k, m; 9 int a[maxn][4]; 10 int tleft, tright; 11 bool check(int x, int y, int x1, int y1) { 12 //cout << x << " " << y << " " << x1 << " " << y1 << endl; 13 if(y < x1 || x > y1) return 0; 14 return 1; 15 } 16 int res; 17 bool f1, f2; 18 void work(vector<pii> & v, bool &f) { 19 f = 0; 20 if(v.size() == 0 || v[0].first > tleft) { 21 f = 1; 22 return; 23 } 24 int cur = tleft, r = tleft; 25 int cnt = 0; 26 int x, y; 27 bool in = 0; 28 for (int i = 0; i < v.size(); i++) { 29 x = v[i].first, y = v[i].second; 30 //cout << x << " " << y << " " << cur << " " << r << endl; 31 if(x > r + 1) { 32 f = 0; return; 33 } 34 if(x <= cur) { 35 if(y >= r) { 36 in = 1; 37 r = y; 38 } 39 if(i == v.size() - 1 && in) { 40 cnt++; 41 r++; 42 } 43 } else { 44 cnt++; 45 r++; 46 if(r > tright) break; 47 cur = r; in = 0; 48 i--; 49 } 50 51 } 52 //cnt++; 53 if(r <= tright) f = 1; 54 //cout << "r " << r << endl; 55 //cout << "cnt " << cnt << endl; 56 res += cnt; 57 } 58 void solve() { 59 scanf("%d%d%d", &n, &k, &m); 60 f1 = f2 = 0; 61 for (int i = 0; i < m; i++) { 62 for (int j = 0; j < 4; j++) 63 scanf("%d", &a[i][j]); 64 } 65 res = 0; 66 tleft = (n - k) / 2 + 1; 67 tright = tleft + k - 1; 68 //cout << tleft << " ads " << tright << endl; 69 vector<pii> v1, v2; 70 for (int i = 0; i < m; i++) { 71 int x, y; 72 x = min(a[i][0], a[i][2]); 73 y = max(a[i][0], a[i][2]); 74 if(check(x, y, tleft, tright)) { 75 //cout << x << " c1 " << y << endl; 76 v1.pb({x, y}); 77 } 78 x = min(a[i][1], a[i][3]); 79 y = max(a[i][1], a[i][3]); 80 if(check(x, y, tleft, tright)) { 81 82 v2.pb({x,y}); 83 } 84 } 85 sort(v1.begin(), v1.end()); 86 v1.erase(unique(v1.begin(), v1.end()), v1.end()); 87 sort(v2.begin(), v2.end()); 88 v2.erase(unique(v2.begin(), v2.end()), v2.end()); 89 work(v1, f1); 90 //cout << "asd" <<endl; 91 work(v2, f2); 92 if(f1 || f2) { 93 puts("-1"); 94 } else { 95 printf("%d\n", res); 96 } 97 } 98 99 int main() {100 //freopen("test.in", "r", stdin);101 //freopen("test.out", "w", stdout);102 int _;103 scanf("%d", &_);104 while(_--)105 solve();106 return 0;107 }108
6. 不会做。 后来发现,题目都没有仔细阅读,条件都没想清楚。 有时间看一下别人的题解吧。
Pre-elimination round B。 也开始了,但是round a过了,就不让做b了,我也没有看。就这样吧。
SnackDown Online Pre-elimination round A