Codeforces Round #652 (Div. 2) 总结

A:问正n边形的一条边和x轴平行的时候有没有一条边和y轴重合,直接判断n是否是4的倍数

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std;


typedef long long ll;
typedef pair<int,int> pi;


int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n;
        scanf("%d", &n);
        if (n % 4 == 0) puts("YES");
        else puts("NO");
    }
}

B题:给一个01串每次可以从连续的“10”中删去0或1(不能同时删去),问可以得到的最小字典序字符串。

字符串中开头的0是去不掉的,末尾的1是去不掉的。中间是1开头的01串,可以发现这堆东西能变成一个"0"。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std;


typedef long long ll;
typedef pair<int,int> pi;
const int N = 1e5 + 100;

char s[N];
int  top;
int n;
char a[N];
void solve() {
    scanf("%d", &n);
    memset(a, 0, sizeof (a));
    memset(s, 0, sizeof (s));
    top = 0;
    scanf("%s", a + 1);
    int f = 0;
    rep(i,1,n) {
        if (!f && a[i] == '0') {
            putchar(a[i]);
            continue;
        }
        if (a[i] == '1') f = 1, s[++top] = a[i];
        if (a[i] == '0') top = 1, s[1] = '0';
    }
    rep(i,1,top) putchar(s[i]);
    puts("");
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
}

C题:给你n个数字,分给k个小伙伴,每个人分得w_i个数字,小伙伴的快乐值是他得到的数字中的最大值加最小值。求所有小伙伴快乐值的和最大是多少。

首先把小伙伴按分得数字个数从小到大排序,数字按从大到小排序。先把最大的k个按这样的顺序分给大家每人一个,然后剩下的数字从第一个小伙伴开始给,到这个小伙伴拿够,给下一个人。 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std;


typedef long long ll;
typedef pair<int,int> pi;
const int N = 2e5 + 100;
int w[N], a[N], n, k;


void solve() {
    scanf("%d %d", &n, &k);
    ll ans = 0;
    rep(i,1,n) scanf("%d", &a[i]);
    rep(i,1,k) scanf("%d", &w[i]);
    sort(a + 1, a + n + 1);
    sort(w + 1, w + k + 1);
    reverse(a + 1, a + n + 1);
    rep(i,1,k) ans += a[i];
    int cnt = k;
    rep(i,1,k) {
        if (w[i] >= 1) {
            if (w[i] == 1) ans += a[i];
            else {
                while (w[i] != 1) {
                    cnt++;
                    w[i]--;
                }
                ans += a[cnt];
            }
        }
    }
    printf("%lld\n", ans);
}
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        solve();
    }
}

D:有一个叫RDB的有根树。一阶RDB只有根结点。i阶RDB是在i-1阶的RDB上发生一些变化:对于没有儿子的节点,长出一个儿子;有一个儿子的节点,再长两个儿子,其余节点不发生变化。钦定一个点和他的三个儿子叫做爪子。然后问你在n阶段RDB上最多能找到多少个不重叠的爪子。

 问题在有三个儿子的结点什么时候会被选什么时候不会被选。当这个结点第一次有三个儿子的时候,选这个结点,一定不比选他的父亲那个结点差,这个时候必选这个结点。更高一阶他中间的儿子结点将有三个儿子,更高两阶他的左右两个儿子会有三个儿子,这时候显然不选这个结点。而更高3阶的时候就会选这个结点。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std;


typedef long long ll;
typedef pair<int,int> pi;
const int N = 2e6 + 100;
const int mod = 1e9 + 7;
ll f[N][10];

void init(){
    f[1][1] = 1;
    rep(i,2,2000000) {
        f[i][5] = f[i-1][4];
        f[i][4] = f[i-1][3];
        f[i][3] = (f[i-1][5] + f[i-1][2]) % mod;
        //temp = f[2];
        f[i][2] = f[i-1][1];
        f[i][1] = (f[i-1][1] + 2 * f[i-1][2]) % mod;
    }
}


void solve() {
    int n;
    scanf("%d", &n);
    printf("%lld\n",f[n][3] * 4 % mod);
}

int main() {
    init();
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
}
View Code

E:你有一些朋友,每个人有两道爱吃的菜x_i, y_i。然后每道菜有w_i份。当一个朋友来的时候会吃ta喜欢的菜,如果有两道就吃两道,有一道就吃一道,如果没有就会吃了你。请问你应该怎么安排朋友吃菜的顺序,来让大家都吃到至少一道自己喜欢吃的菜,或者无论怎么安排都会有人吃不到。

设喜欢吃某道菜的人数为s_i,如果所有的s_i 都小于 w_i那么就无解,显然最后一个人的菜一定都被别人吃光了。对于wi >= si的菜,这些人多会吃都有关系。所以我们放在后面,这样他们就会吃的少一点。然后按照这种方法一直做就好了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std;


typedef long long ll;
typedef pair<int,int> pi;
const int N = 2e5 + 100;
const int mod = 1e9 + 7;

int n, m;
vector<int> d[N];
int s[N], w[N], a[N], b[N], vis[N];
int ans[N], cnt = 0;
int main() {
    scanf("%d%d", &n, &m);
    rep(i,1,n) scanf("%d", &w[i]);
    rep(i,1,m) {
        scanf("%d %d", &a[i], &b[i]);
        s[a[i]]++;
        s[b[i]]++;
        d[a[i]].push_back(i);
        d[b[i]].push_back(i);
    }
    queue<int> q;
    rep(i,1,n) if (s[i] <= w[i]) q.push(i);
    while (!q.empty()) {
        int j = q.front(); q.pop();
        int _ = (int)d[j].size();
        rep(i,0,_-1) {
            if (!vis[d[j][i]]) {
                int u = a[d[j][i]], v = b[d[j][i]];
                if (u == j) swap(u, v);
                s[u]--;
                if (s[u] == w[u]) q.push(u);
                vis[d[j][i]] = 1;
                ans[++cnt] = d[j][i];
            }  
        }
    }
    if (cnt < m) {
        puts("DEAD");
        return 0;
    }
    puts("ALIVE");
    reverse(ans + 1, ans + cnt + 1);
    rep(i,1,cnt) printf("%d ", ans[i]); puts("");
}

f题:有一个游戏,有两个数s,e每次可以把s变成s + 1或者是s * 2,当s大于e时,就输了。有n轮游戏,每轮游戏输的人先手开始下一轮游戏。在最后一轮赢了的人,赢得了游戏。在最后一轮输的人,输掉了游戏。

问先手能否必胜,同时先手能否一定失败。

定义一下win(s,e)和lose(s,e)表示先手是否能一定赢和一定输。

e是奇数的时候s奇数必败s是偶数必胜。(可以自己写一写看一下)。e是偶数的时候,s大于e/2,s是奇数必胜,偶数必败。s大于e/4的时候,无论s是什么都能必胜。否则就是win(s, e/4)

对于先手强制输的情况,如果s * 2 > e一定可以输,否则等价于win(s, e / 2)

然后对于游戏的输赢就是,就是从最后局开始递归,如果这局能先手必胜(败),上一局就必须要输,否则上一局就必须要赢。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <map>
 7 #include <cmath>
 8 #include <queue>
 9 #include <set>
10 #define rep(i,j,k) for(int i = j; i <= k; i++)
11 #define dow(i,j,k) for(int i = j; i >= k; i--)
12 #define ez(i,x) for(int i = h[x]; i; i = e[i].next)
13 #define fi first
14 #define se second
15 using namespace std;
16 
17 
18 typedef long long ll;
19 typedef pair<int,int> pi;
20 
21 const int N = 1e5 + 100;
22 ll e[N], s[N];
23 bool w[N], l[N];
24 int n;
25 
26 bool Win(ll s, ll e) {
27     if ((e & 1)) {
28         if (s & 1) return 0;
29         return 1;
30     }
31     if (s > e) return 1;
32     if (s * 2 > e) return (bool)(s & 1);
33     if (s * 4 > e) return 1;
34     return Win(s, e / 4);
35 }
36 
37 bool Lose(ll s, ll e) {
38     if (s * 2 > e) return 1;
39     return Win(s, e / 2);
40 }
41 
42 int getWin(int);
43 int getLose(int);
44 
45 int getWin(int x) {
46     if (x == 1) return (int)w[1];
47     return w[x]? getLose(x - 1) : getWin(x - 1);
48 }
49 
50 int getLose(int x) {
51     if (x == 1) return (int)l[1];
52     return l[x]? getLose(x - 1) : getWin(x - 1);
53 }
54 int main() {
55     //ios::sync_with_stdio(0);
56     scanf("%d", &n);
57     rep(i,1,n) {
58         scanf("%lld %lld", &s[i], &e[i]);
59         w[i] = Win(s[i], e[i]);
60         l[i] = Lose(s[i], e[i]);
61       //  cout << w[i] << " " << l[i] << endl;
62     }
63     printf("%d %d\n",getWin(n), getLose(n));

猜你喜欢

转载自www.cnblogs.com/Fermat/p/13199033.html