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_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 }
View Code

 

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 }
View Code

 

 

 

 

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;
}
View Code

 

同样利用单调栈的一道题:HDU 5033 Building

 

posted on 2014-09-26 23:18  rootial  阅读(180)  评论(0编辑  收藏  举报

导航