首页 > 代码库 > Codeforces Round #238 (Div. 1)
Codeforces Round #238 (Div. 1)
感觉这场题目有种似曾相识感觉,C题还没看,日后补上。一定要坚持做下去。
A
Unusual Product
题意:
给定一个n*n的01矩阵,3种操作,
1 i 将第i行翻转
2 i 将第i列翻转
3 询问矩阵第i行和第i列做向量乘法之和。
分析:
分析发现对于3的结果取决于对角线上1的个数num,即num%2,然后就很好做了,对于每次操作,只需要改变该行或该列后,对角线上仍然有多少个1.
代码:
1 #pragma comment(linker, "/STACK:16777216") 2 #include <cstdio> 3 #include <iostream> 4 #include <cstring> 5 #include <queue> 6 #include <vector> 7 #include <cmath> 8 #define inf 0x0f0f0f0f 9 #define in freopen("data.txt", "r", stdin);10 #define pb push_back11 #define bug(x) printf("Line : >>>>%d\n", (x));12 using namespace std;13 typedef unsigned short US;14 typedef long long LL;15 const int maxn = 1111;16 int vis[maxn];17 18 int main(){19 20 int n, q;21 scanf("%d", &n);22 int res = 0;23 for(int i = 0; i< n; i++) for(int j = 0; j < n; j++) {24 int t;25 scanf("%d", &t);26 if(i == j) vis[i] = t, res += t;27 }28 scanf("%d", &q);29 while(q--){30 int t, x;31 scanf("%d", &t);32 if(t != 3){33 scanf("%d", &x);34 vis[x] ^= 1;35 res += (vis[x] ? 1 : -1);36 }37 else{38 cout<<res%2;39 }40 }41 cout<<endl;42 return 0;43 }
B
Toy Sum
题意:
共有1,2,3到10^6这么些个数首先选出n个数,x1~xn,要从剩下的数中选出若干数满足灯饰sum{xi-1| 1 <= i <= n} = sum {s-yi|1 <= i <= m}
分析:
xi-1和s-yi分别表示的数到两端的距离。
那么对于xi如果离s一样的近的数没有被选中则优先选它,如果两端一样近的地方都选取了,先不管它。最后将能够选取的一样近的数都选取完毕后,再针对两端一样近的数都选了的情况,这时候也只要将两端一样近的从没选中的选进Y集合就行了。
上面这样似乎才是标准解法,可是我是dfs暴力求解,加了些剪枝,也能过。
我的代码:
1 #pragma comment(linker, "/STACK:16777216") 2 #include <cstdio> 3 #include <iostream> 4 #include <cstring> 5 #include <bitset> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <cmath>10 #define inf 0x0f0f0f0f11 #define in freopen("data.txt", "r", stdin);12 #define pb push_back13 #define bug(x) printf("Line : >>>>%d\n", (x));14 using namespace std;15 typedef unsigned short US;16 typedef long long LL;17 const int maxn = (int)1e6 + 100;18 LL a[maxn];19 bitset<maxn> vis;20 LL sum[maxn];21 int ok;22 vector<int> ans;23 int s = (int)1e6;24 25 void dfs(int x, LL sm) {26 if(ok) return;27 if(sm == 0) {28 ok = 1;29 return;30 }31 int k = upper_bound(a+1, a+x+1, sm) - a;32 k--;33 for(int i = k; i >= 1 && sum[i] >= sm; i--) {34 ans.pb(s-a[i]);35 dfs(i-1, sm-a[i]);36 if(ok) return;37 ans.pop_back();38 }39 }40 int main() {41 42 int n;43 scanf("%d", &n);44 LL tmp = 0;45 for(int i = 1; i <= n; i++) {46 int u;47 scanf("%d", &u);48 tmp += u-1;49 vis[u] = 1;50 }51 52 // cout<<tmp<<endl;53 int cnt = 0;54 for(int i = s; i >= 1; i--)55 if(vis[i] == 0) {56 a[++cnt] = s-i;57 // if(cnt <= 10)58 // cout<<a[cnt]<<endl;59 sum[cnt] = sum[cnt-1] + s-i;60 }61 vis.reset();62 if(tmp == 0) {63 cout<< 1 <<endl;64 cout<< 1000000 << endl;65 return 0;66 }67 dfs(cnt, tmp);68 printf("%d\n", ans.size());69 70 for(int i = 0; i < ans.size(); i++)71 printf("%d%c", ans[i], i == ans.size()-1 ? ‘\n‘ : ‘ ‘);72 return 0;73 }
D
Hill Climbing
题意:
每座山用一根垂直线段表示,有x,y两种属性,按照x递增给定n座山的xi和yi,每次在第i座山的时候只能够到达在视野范围内(这样说是没有问题的)的最右的一座山,然后两个人分别位于两座山上,问他们分别出发,沿着上面的原则确定的路线转移,直到两者到达同一座山。
分析:
首先要确定没座山能够到达的最右的一座山,除了最右的山没有可到达的山,每座山显然能到达另一座山,可以从右往左扫,建立单调栈,将第i座山与栈顶的斜率k1,栈顶与栈顶以下的一座山的斜率k2比较,如果k1 < k2将栈顶元素出栈。最后第i座山能够到达栈顶那座山,同时将i入栈。
这样会得到一棵树,对于每个询问,只需要询问他们的lca就是了。
注意:倍增法求lca的时候,应该在dfs子树的时候将fa[u][i]更新求出来。
代码:
#pragma comment(linker, "/STACK:16777216")#include <cstdio>#include <iostream>#include <cstring>#include <bitset>#include <algorithm>#include <queue>#include <vector>#include <cmath>#define inf 0x0f0f0f0f#define in freopen("data.txt", "r", stdin);#define pb push_back#define esp 1e-6#define bug(x) printf("Line : >>>>%d\n", (x));using namespace std;typedef unsigned short US;typedef long long LL;const int maxn = (int)1e5 + 100;struct Po { double x, y;} h[maxn];int st[maxn];vector<int> g[maxn];double cal(int x, int y) { return (h[x].y-h[y].y)/(h[x].x-h[y].x);}int fa[maxn][20], dep[maxn];double dblcmp(double x) { if(fabs(x) < esp) return 0; return x > 0 ? 1 : -1;}void dfs(int u, int f) { dep[u] = dep[f] + 1; fa[u][0] = f; for(int i = 1; i < 20; i++) { fa[u][i] = fa[fa[u][i-1]][i-1]; } for(int i = 0; i < g[u].size(); i++) { int v = g[u][i]; if(v == f) continue;// cout<<v<<endl; dfs(v, u); }}int lca(int x, int y) { if(dep[x] < dep[y]) swap(x, y); int d = dep[x]-dep[y]; for(int i = 0; i < 20; i++) if((d &(1<<i))) x = fa[x][i]; if(x != y) { for(int i = 19; i >= 0; i--) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; x = fa[x][0]; } return x;}int main() { int n, q; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%lf%lf", &h[i].x, &h[i].y); } int top = 0; for(int i = n; i >= 1; i--) { while(top >= 2 && dblcmp(cal(i, st[top]) - cal(st[top], st[top-1])) < 0) top--; if(top) { g[st[top]].pb(i); g[i].pb(st[top]); } st[++top] = i; } dfs(n, 0); scanf("%d", &q); for(int i = 1; i <= q; i++) { int u, v; scanf("%d%d", &u, &v); printf("%d%c", lca(u, v), i == q ? ‘\n‘ : ‘ ‘); } return 0;}
同样利用单调栈的一道题:HDU 5033 Building
Codeforces Round #238 (Div. 1)