感觉这场题目有种似曾相识感觉,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_back 11 #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 0x0f0f0f0f 11 #define in freopen("data.txt", "r", stdin); 12 #define pb push_back 13 #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