其他-学长杂题讲义

1. Rasheda And The Zeriba

大致题意: 给出n条边,判断能否构成一个n边凸多边形,并求出能覆盖该图形的圆的最小半径 1 ≤ n ≤ 1000 。

http://codeforces.com/gym/100283/problem/A 

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 int N;
 8 double R[1005];
 9 const double _pi = asin(1)*2;
10 
11 bool Check(double v)
12 {
13     double tmp = 0; int i;
14     for (i = 1; i <= N; ++i)
15         if ((tmp += asin(R[i]/2/v)*2) > 2*_pi) break;
16     return i == N+1;
17 }
18 
19 int main()
20 {
21     freopen("zeriba.in", "r", stdin);
22     int T;
23     scanf("%d", &T);
24     for (int ca = 1; ca <= T; ++ca) {
25         scanf("%d", &N);
26         double sum = 0, mx = 0; int i;
27         for (i = 1; i <= N; ++i)
28             scanf("%lf", &R[i]), sum += R[i], mx = max(mx, R[i]);
29         for (i = 1; i <= N; ++i)
30             if (sum-R[i] <= R[i]) break;
31         if (i != N+1) { printf("Case %d: can't form a convex polygon\n", ca); continue; }
32         double l = mx/2, r = sum/4;
33         while (fabs(l-r) >= 0.000001) {
34             double mid = (l+r)/2;
35             if (Check(mid)) r = mid;
36             else l = mid;
37         }
38         printf("Case %d: %.4lf\n", ca, l);
39     }
40     return 0;
41 }
View Code

 

 2. Fitting boxes

大致题意:给出两个矩形长宽(1 <= x, y, a, b <= 1000),判断能否使其中一个完全覆盖另一个。

http://codeforces.com/gym/100738/problem/A

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <algorithm>
 4 
 5 const double _PI = asin(1)*2;
 6 
 7 using namespace std;
 8 
 9 inline double P(double v) { return v * v; }
10 
11 bool Test(double x, double y, double a, double b)
12 {
13     if (x*y < a*b || a > x) return false;
14     if (b <= y) return true;
15     if (P(y*b) < P(a*a)+P(a*b)-P(a*y)) return false;
16     
17     double tmp = _PI/2 - (atan(sqrt(P(y)/(P(a)+P(b)-P(y)))) - atan(a/b));
18     double tmp2 = b*sin(tmp)+a*cos(tmp);
19     return 0 <= tmp2 && tmp2 <= x;
20 }
21 
22 int main()
23 {
24     double t1, t2, t3, t4;
25     int ans = 0;
26     scanf("%lf%lf%lf%lf", &t1, &t2, &t3, &t4);
27 
28     ans |= Test(t1, t2, t3, t4);
29     ans |= Test(t1, t2, t4, t3);
30     ans |= Test(t2, t1, t3, t4);
31     ans |= Test(t2, t1, t4, t3);
32     
33     swap(t1, t3), swap(t2, t4);
34     
35     ans |= Test(t1, t2, t3, t4);
36     ans |= Test(t1, t2, t4, t3);
37     ans |= Test(t2, t1, t3, t4);
38     ans |= Test(t2, t1, t4, t3);
39     
40     if (ans) printf("Yes\n");
41     else printf("No\n");
42     return 0;
43 }
View Code

 

3. Pretty Buses

大致题意:一个n个点m条边的无向图,每条边有一个权值。初始时,点i处有巴士i和司机i,你可以有两种操作:(1)Drive b x y,把巴士b从x点开到y点并付出这条边的权值的费用;(2)Move d x y,司机d从巴士x移动的巴士y上,没有花费 所有司机要集中在一个点,并且每个司机的换乘次数不多于25 求最小花费,并给出一种合理的方案 1 ≤ n ≤ 200000, 1 ≤ m ≤ 400000

http://codeforces.com/gym/100738/problem/E

#include <cstdio>
#include <queue>
#include <vector>

using namespace std;

const int _N = 400005;

struct tmpeg {
    int x, y, w;
    tmpeg(int x, int y, int w):
        x(x), y(y), w(w) { }
    bool operator < (const tmpeg t) const
    {
        return w > t.w;
    }
};

priority_queue<tmpeg> Q;
vector<int> G[_N], dri[_N];
int veh[_N], siz[_N], Dad[_N];

inline void Ins(int x, int y) { G[x].push_back(y); return; }

void diudiu(int node, int dad)
{
    int mx = node;
    for (int i = G[node].size()-1; i >= 0; --i) {
        int v = G[node][i];
        if (v == dad) continue;
        diudiu(v, node);
        printf("Drive %d %d %d\n", veh[v], v, node);
        int a = veh[node], b = veh[v];
        if (siz[a] < siz[b]) swap(a, b);
        veh[node] = veh[v] = a;
        siz[a] += siz[b];
        for (int j = dri[b].size()-1; j >= 0; --j) {
            printf("Move %d %d %d\n", dri[b][j], b, a);
            dri[a].push_back(dri[b][j]), veh[dri[b][j]] = a;
        }
        
    }
    return;
}

int GetDad(int v) { return Dad[v] == v ? v : Dad[v] = GetDad(Dad[v]); }

int main()
{
    int N, M, i;
    scanf("%d%d", &N, &M);
    for (i = 1; i <= M; ++i) {
        int x, y, w;
        scanf("%d%d%d", &x, &y, &w);
        Q.push(tmpeg(x, y, w));
    }
    long long ans = 0; int cnt = 0;
    for (i = 1; i <= N; ++i)
        Dad[i] = i, siz[i] = 1, veh[i] = i, dri[i].push_back(i);
    while (true) {
        tmpeg tmp = Q.top(); Q.pop();
        int tx = GetDad(tmp.x), ty = GetDad(tmp.y);
        if (tx != ty) {
            Dad[tx] = ty, Ins(tmp.x, tmp.y), Ins(tmp.y, tmp.x);
            ++cnt, ans += tmp.w;
            if (cnt == N-1) break;
        }
    }
    printf("%I64d\n", ans);
    
    diudiu(1, 0);
    printf("Done\n");
    return 0;
}
View Code

 

4. Mishka and Interesting sum

大致题意:询问数列 A 中 [L, R] 区间出现次数为偶数次的数字,每个数只算一次的异或和。比如对于 {1, 3, 3, 3, 4, 4} ,答案是 1^3^4 。

http://codeforces.com/contest/703/problem/D

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 using namespace std;
 5 
 6 const int _N = 1050000;
 7 
 8 struct query {
 9     int l, r, id;
10     bool operator < (const query tmp) const
11     {
12         return this->l < tmp.l;
13     }
14 } Q[_N];
15 
16 int pos, N, M, N_A;
17 int A[_N], B[_N], C[_N], sum[_N], fst[_N], nxt[_N], ans[_N];
18 bool mk[_N];
19 
20 void Add(int k, int d)
21 {
22     for (int i = k; i <= N; i += i & -i)
23         C[i] ^= d;
24     return;
25 }
26 
27 int GetSum(int k)
28 {
29     int tmp = 0;
30     for (int i = k; i; i ^= i & -i)
31         tmp ^= C[i];
32     return tmp;
33 }
34 
35 int hs(int v) { return lower_bound(A+1, A+1+N_A, v)-A; }
36 
37 int main()
38 {
39     int i;
40     scanf("%d", &N);
41     for (i = 1; i <= N; ++i)
42         scanf("%d", &A[i]), sum[i] = sum[i-1]^A[i], B[i] = A[i];
43     scanf("%d", &M);
44     for (i = 1; i <= M; ++i)
45         scanf("%d%d", &Q[i].l, &Q[i].r), Q[i].id = i;
46     
47     sort(Q+1, Q+1+M);
48     sort(A+1, A+1+N);
49     N_A = unique(A+1, A+1+N)-A-1;
50     for (i = 1; i <= N; ++i) {
51         int tmp;
52         if (!mk[tmp = hs(B[i])])
53             mk[tmp] = true, Add(i, B[i]);
54     }
55     pos = 1;
56     for (i = N; i >= 1; --i) {
57         int tmp = hs(B[i]);
58         nxt[i] = fst[tmp], fst[tmp] = i;
59     }
60     
61     for (i = 1; i <= M; ++i) {
62         while (pos < Q[i].l) {
63             Add(pos, B[pos]);
64             if (nxt[pos]) Add(nxt[pos], B[pos]);
65             ++pos;
66         }
67         ans[Q[i].id] = GetSum(Q[i].r)^sum[Q[i].r]^sum[Q[i].l-1];
68     }
69     for (i = 1; i <= M; ++i)
70         printf("%d\n", ans[i]);
71     return 0;
72 }
View Code

 

5. Queries

大致题意:维护一个序列,支持 1.单点修改 2.查询某区间 [l, r] 中所有合理的 [i, j] (l <= i <= j <= r) 的异或结果的和。用 Elf(i, j) 表示 [i, j] 中所有数的异或结果,则 [l, r] 查询的结果应为 ∑Elf(i, j)  ( [i, j] ⊆ [l, r] ) 。

http://codeforces.com/gym/100739/problem/A

一定注意,尽管根据定义 lsum0(表示左起前缀和中 0 的个数) = 区间长度 - lsum1 (表示左起前缀和中 1 的个数),但是最好在线段树中同时维护这两个变量,这样在查询操作时可以避免一些特判。理论上只记一个变量+特判是可以的,我最初也是这么写的,也就 Wa 了那么七八次吧,还要感谢 newuser 大佬指出我特判的愚蠢性……OrzOrzOrz

 1 #include <cstdio>
 2 
 3 const int MOD = 4001;
 4 const int _N = 2800000;
 5 
 6 int Tot, N, M;
 7 int lsum0[_N], lsum[_N], rsum0[_N], rsum[_N], xos[_N], cnt[_N], lson[_N], rson[_N], root[11];
 8 
 9 void Modify(int &p, int l, int r, int k, int v)
10 {
11     if (!p) p = ++Tot;
12     if (l == r) { lsum[p] = rsum[p] = cnt[p] = xos[p] = v, lsum0[p] = rsum0[p] = v^1; return; }
13     int mid = l+r >> 1;
14     if (!lson[p]) lson[p] = ++Tot;
15     if (!rson[p]) rson[p] = ++Tot;
16     if (k <= mid) Modify(lson[p], l, mid, k, v);
17     else Modify(rson[p], mid+1, r, k, v);
18     lsum[p] = (lsum[lson[p]] + (xos[lson[p]] ? lsum0[rson[p]] : lsum[rson[p]]))%MOD;
19     rsum[p] = (rsum[rson[p]] + (xos[rson[p]] ? rsum0[lson[p]] : rsum[lson[p]]))%MOD;
20     lsum0[p] = (lsum0[lson[p]] + (xos[lson[p]] ? lsum[rson[p]] : lsum0[rson[p]]))%MOD;
21     rsum0[p] = (rsum0[rson[p]] + (xos[rson[p]] ? rsum[lson[p]] : rsum0[lson[p]]))%MOD;
22     xos[p] = xos[lson[p]] ^ xos[rson[p]];
23     cnt[p] = (cnt[lson[p]]+cnt[rson[p]])%MOD;
24     cnt[p] = (cnt[p]+rsum[lson[p]]*lsum0[rson[p]]%MOD)%MOD;
25     cnt[p] = (cnt[p]+rsum0[lson[p]]*lsum[rson[p]]%MOD)%MOD;
26     return;
27 }
28 
29 int Query(int &p, int l, int r, int s, int t, int &tmp_l, int &tmp_r, int &tmp_x, int &tmp_l0, int &tmp_r0)
30 {
31     if (!p) p = ++Tot;
32     if (s <= l && r <= t) { tmp_l = lsum[p], tmp_r = rsum[p], tmp_x = xos[p], tmp_l0 = lsum0[p], tmp_r0 = rsum0[p]; return cnt[p]; }
33     int mid = l+r >> 1, l_l=0, l_r=0, l_x=0, r_l=0, r_r=0, r_x=0, l_cnt=0, r_cnt=0, l_l0=0, l_r0=0, r_l0=0, r_r0=0;
34     if (t >= l && s <= mid) l_cnt = Query(lson[p], l, mid, s, t, l_l, l_r, l_x, l_l0, l_r0);
35     if (t > mid && s <= r) r_cnt = Query(rson[p], mid+1, r, s, t, r_l, r_r, r_x, r_l0, r_r0);
36     
37     tmp_l = (l_l + (l_x ? r_l0 : r_l))%MOD;
38     tmp_r = (r_r + (r_x ? l_r0 : l_r))%MOD;
39     tmp_l0 = (l_l0 + (l_x ? r_l : r_l0))%MOD;
40     tmp_r0 = (r_r0 + (r_x ? l_r : l_r0))%MOD;
41     tmp_x = l_x ^ r_x;
42     int tmp_cnt = (l_cnt+r_cnt)%MOD;
43     tmp_cnt = (tmp_cnt+l_r*r_l0%MOD)%MOD;
44     tmp_cnt = (tmp_cnt+l_r0*r_l%MOD)%MOD;
45     return tmp_cnt;
46 }
47 
48 int main()
49 {
50     int i, j;
51     scanf("%d%d", &N, &M);
52     for (i = 1; i <= N; ++i) {
53         int tmp;
54         scanf("%d", &tmp);
55         for (j = 0; j < 11; ++j)
56             Modify(root[j], 1, N, i, (tmp>>j)&1);
57     }
58     while (M--) {
59         int ins, x, y;
60         scanf("%d%d%d", &ins, &x, &y);
61         if (ins == 1) {//change
62             for (j = 0; j < 11; ++j)
63                 Modify(root[j], 1, N, x, (y>>j)&1);
64         } else {//query
65             int ans = 0;
66             int tl, tr, tx, tl0, tr0;
67             for (j = 0; j < 11; ++j)
68                 ans = (ans+(Query(root[j], 1, N, x, y, tl, tr, tx, tl0, tr0)<<j)%MOD)%MOD;
69             printf("%d\n", (ans+MOD)%MOD);
70         }
71     }
72     return 0;
73 }
View Code

 

6. Decomposition into Good Strings

大致题意:定义 good string 为正好包含 k 种不同字母的字符串(如当 k = 2 时,abbbba 是一个 good string)。给定 k 和一个长为 n (1 <= n <= 200000)的字符串,求该字符串的每个前缀最少可以被分割为多少个 good string 。即输出 n 个数,分别对应原字符串的 n 个前缀的答案。

http://codeforces.com/gym/100971/problem/M

 1 #include <cstdio>
 2 
 3 char A[250000];
 4 int f[250000], mk[300], cnt, K, pos;
 5 
 6 void Update(int i)
 7 {
 8     if (++mk[A[i]] == 1) ++cnt;
 9     if (cnt < K) { f[i] = -1; return; }
10     while (cnt > K) {
11         if (!--mk[A[pos]]) --cnt;
12         ++pos;
13     }
14     if (pos == -1) pos = 1;
15     bool flag = false;
16     while (f[pos-1] == -1) {
17         if (mk[A[pos]] == 1) { flag = true; break; }
18         --mk[A[pos]], ++pos;
19     }
20     if (flag) { f[i] = -1; return; }
21     f[i] = f[pos-1]+1;
22     return;
23 }
24 
25 int main()
26 {
27     char tt;
28     int i;
29     scanf("%d", &K);
30     f[0] = 0, pos = -1;
31     while ((tt = getchar()) < 'a' || tt > 'z');
32         A[i = 1] = tt, Update(i);
33     while ((tt = getchar()) >= 'a' && tt <= 'z')
34         A[++i] = tt, Update(i);
35     for (int t = 1; t <= i; ++t)
36         printf("%d ", f[t]);
37     return 0;
38 }
View Code

 

posted @ 2018-07-07 20:50  derchg  阅读(226)  评论(0编辑  收藏  举报