第一场选拔赛 [2013, VI Samara Regional Intercollegiate Programming Contest]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chenzhenyu123456/article/details/63686581

A
题意: n 瓶药里面有一瓶生药,每次会选择 k 瓶给兔子服用,只有这 k 瓶中有该生药,这个兔子才不会死。问最坏的情况下最少要死多少只兔子才可以确定哪一瓶是生药。

思路:推推就会发现和 n k 有关, 特判 n = k k = 1 的情况

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
int main()
{
    int n, k; scanf("%d%d", &n, &k);
    if(n == k) {
        if(n == 1) {
            printf("0\n");
        }
        else {
            printf("-1\n");
        }
    }
    else {
        if(k == 1) {
            printf("%d\n", n - 1);
        }
        else if(n % k == 0 || n % k == 1) {
            printf("%d\n", n / k);
        }
        else {
            printf("%d\n", n / k + 1);
        }
    }
    return 0;
}

B
题意:给定两个只有小写字母的相等的字符串,每次从两个字符串中分别取出一个字母(直到取完为止),问取出相等字母次数的期望。

思路:概率论的知识,但我是猜的结果。原谅我数学知识全还给老师了……

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
char str[200000 + 10];
int num[30];
int main()
{
    scanf("%s", str);
    int len = strlen(str);
    memset(num, 0, sizeof(num));
    for(int i = 0; i < len; i++) {
        num[str[i] - 'a']++;
    }
    double ans = 0;
    for(int i = 0; i < 26; i++) {
        ans += num[i] * 1.0 / len * num[i];
    }
    printf("%.15lf\n", ans);
    return 0;
}

C
没写

D
题意:从 n 个人选出若干个,构成两个非空集合,一个集合送礼物,另一个集合接受礼物。问方案数。

思路: i = 2 n C n i ( 2 i 2 )

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
const int MAXN = 200000 + 10;
const int MOD = 1e9 + 9;
void add(LL &x, LL y) { x += y; if(x >= MOD) x -= MOD; }
LL f[MAXN], s[MAXN];
LL pow_mod(LL a, int n) {
    LL ans = 1;
    while(n) {
        if(n & 1) {
            ans = ans * a % MOD;
        }
        a = a * a % MOD;
        n >>= 1;
    }
    return ans;
}
LL C(int n, int m) {
    return f[n] * pow_mod(f[m], MOD - 2) % MOD * pow_mod(f[n - m], MOD - 2) % MOD;
}
LL Work(LL n) {
    if(n < 0) {
        n += MOD;
    }
    return n;
}
int main()
{
    int n; scanf("%d", &n);
    f[0] = 1; s[0] = 1;
    for(int i = 1; i <= n; i++) {
        f[i] = f[i - 1] * i % MOD;
        s[i] = s[i - 1] * 2 % MOD;
    }
    LL ans = 0;
    for(int i = 2; i <= n; i++) {
        add(ans, C(n, i) * Work(s[i] - 2) % MOD);
    }
    printf("%lld\n", ans);
    return 0;
}

E
题意:问你两个图是否存在相同的最短路径。
解法一:对每个图跑一次BFS,再把两个图合起来再跑一次BFS,最后 c h e c k 一下
解法二:对每个跑一次BFS,然后总的 c h e c k

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
struct Node {
    int x, y;
    Node() {}
    Node(int a, int b) : x(a), y(b) {}
};
char str[2][502][502];
int dis[2][502][502];
int n, m;
bool judge(int id, Node a) {
    if(a.x < 0 || a.x >= n) return false;
    if(a.y < 0 || a.y >= m) return false;
    if(dis[id][a.x][a.y] != -1) return false;
    if(str[id][a.x][a.y] == '#') return false;
    return true;
}

int ne[4][2] = {0,1, 0,-1, 1,0, -1,0};
Node p, q;
queue<Node> Q;

void BFS(int id) {

    Q.push(Node(0, 0)); dis[id][0][0] = 0;

    while(!Q.empty()) {
        p = Q.front(); Q.pop();
        if(p.x == n - 1 && p.y == m - 1) {
            continue;
        }
        for(int i = 0; i < 4; i++) {
            q = Node(p.x + ne[i][0], p.y + ne[i][1]);
            if(judge(id, q)) {
                dis[id][q.x][q.y] = dis[id][p.x][p.y] + 1;
                Q.push(q);
            }
        }
    }
}
bool d[502][502];
void Check() {
    memset(d, false, sizeof(d));
    Q.push(Node(0, 0)); d[0][0] = true;
    while(!Q.empty()) {
        p = Q.front(); Q.pop();
        if(p.x == n - 1 && p.y == m - 1) {
            printf("YES\n");
            return;
        }
        for(int i = 0; i < 4; i++) {
            q = Node(p.x + ne[i][0], p.y + ne[i][1]);

            if(q.x < 0 || q.x >= n || q.y < 0 || q.y >= m || d[q.x][q.y]) {
                continue;
            }

            bool flag = true;
            for(int j = 0; j < 2; j++) {
                if(dis[j][q.x][q.y] != dis[j][p.x][p.y] + 1) {
                    flag = false;
                    break;
                }
            }
            if(flag) {
                d[q.x][q.y] = true;
                Q.push(q);
            }
        }
    }
    printf("NO\n");
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++) {
        scanf("%s", str[0][i]);
    }
    for(int i = 0; i < n; i++) {
        scanf("%s", str[1][i]);
    }
    memset(dis, -1, sizeof(dis));
    BFS(0); BFS(1), Check();
    return 0;
}

F
题意: n 个人和 m 个避难所在一条直线上,每个避难所可以容纳 k 个人。现在有 t 秒时间,最多多少人获救。
思路:从前向后贪心即可。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 200000 + 10;
int a[MAXN], b[MAXN];
int main()
{
    int n, m, k, t; scanf("%d%d%d%d", &n, &m, &k, &t);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for(int i = 1; i <= m; i++) {
        scanf("%d", &b[i]);
    }

    sort(a + 1, a + n + 1);
    sort(b + 1, b + m + 1);

    int ans = 0;
    int now = 1, use = k;
    for(int i = 1; i <= n && now <= m; i++) {

        while(now <= m && b[now] <= a[i]) {
            if(a[i] - b[now] <= t && use) {
                break;
            }
            now++; use = k;
        }

        if(use == 0) {
            now++; use = k;
        }

        if(now <= m) {
            if(b[now] <= a[i]) {
                if(a[i] - b[now] <= t && use) {
                    ans++; use--;
                }
            }
            else {
                if(b[now] - a[i] <= t && use) {
                    ans++; use--;
                }
            }
        }
    }

    printf("%d\n", ans);

    return 0;
}

G
没写

H
题意:给定两个由三个点组成的三角形,问是否相似。

思路:算出边长的平方,比较即可。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
LL x[6], y[6];
LL d[6];
LL Dis(int i, int j) {
    return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
}
bool Check() {
    int cnt = 0;
    for(int i = 0; i < 2; i++) {
        for(int j = i + 1; j < 3; j++) {
            d[cnt++] = Dis(i, j);
        }
    }
    for(int i = 3; i < 5; i++) {
        for(int j = i + 1; j < 6; j++) {
            d[cnt++] = Dis(i, j);
        }
    }
    sort(d, d + 3);
    sort(d + 3, d + 6);
    return d[0] * d[4] == d[1] * d[3] && d[0] * d[5] == d[2] * d[3];
}
int main()
{
    for(int i = 0; i < 6; i++) {
        scanf("%lld%lld", &x[i], &y[i]);
    }
    printf(Check() ? "YES\n" : "NO\n");
    return 0;
}

I
没写

J
题意: n 张牌, k 个洗牌机,问你能否将牌 x 洗到第一个位置。

思路:建一个有向图,然后DFS即可。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 200000 + 10;
int n, m;
int a[MAXN];
bool vis[MAXN];
vector<int> G[MAXN];
bool Check(int u) {
    if(u == 1) {
        return true;
    }
    vis[u] = true;
    for(int i = 0; i < (int)G[u].size(); i++) {
        int v = G[u][i];
        if(vis[v]) continue;
        if(Check(v)) {
            return true;
        }
        // vis[v] = false;
    }
    return false;
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        vis[i] = false; G[i].clear();
    }
    scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        for(int j = 1; j <= n; j++) {
            int v; scanf("%d", &v);
            G[v].push_back(j);
        }
    }

    int pos; scanf("%d", &pos);
    for(int i = 1; i <= n; i++) {
        if(a[i] == pos) {
            pos = i;
            break;
        }
    }
    printf(Check(pos) ? "YES\n" : "NO\n");
    return 0;
}

K
题意: n 个发射端, n 个接收端。发射的都是直线,若直线交叉一次释放一焦耳能量。让你制定一个发射序列,使得正好释放 k 焦耳能量。

思路:其实就是一个逆序对。
证明一下:
假设当前发射端为 i ,发射序列为 a [ i ] 。对于后面的发射序列元素 a [ j ] ( j > i ) ,若 a [ j ] > a [ i ] ,那么这两条发射线一定不会相交;反之必定相交。
这样就相当于求解每个元素后面有多少个元素比它大,也就是逆序对。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 200000 + 10;
int a[MAXN];
int main()
{
    int n; LL k; scanf("%d%lld", &n, &k);
    int Max = n;
    int val = 1;
    int i, j, num = n - 1;
    for(i = 1; i <= n; i++, num--) {
        if(k >= num) {
            a[i] = Max;
            k -= num; 
            Max--;
        }
        else {
            a[i] = val;
            val++;
        }
    }
    for(i = 1; i <= n; i++) {
        if(i > 1) printf(" ");
        printf("%d", a[i]);
    }
    printf("\n");
    return 0;
}

L
题意:构造回文串。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
const int MAXN = 200000 + 10;
char str[MAXN];
int main()
{
    scanf("%s", str);
    int len = strlen(str);
    for(int i = 0; i < len / 2; i++) {
        if(str[i] != str[len - i - 1]) {
            str[i] = str[len - i - 1];
        }
    }
    printf("%s\n", str);
    return 0;
}

M
题意: f ( x ) = θ ( s 1 x a 1 ) + θ ( s 2 x a 2 ) + . . . + θ ( s n x a n ) ,其中
θ ( x ) = { 1 x >= 0 0 x < 0  ,每次给出一个 x ,查询 f ( x ) 结果。

思路:根据 s 1 1 的情况,把序列 a [ ] 分成两个集合,然后二分即可。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <set>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 200000 + 10;
int a[MAXN], b[MAXN];
int main()
{
    int n; scanf("%d", &n); 
    int la = 0, lb = 0;
    for(int i = 1; i <= n; i++) {
        int s, v;
        scanf("%d%d", &s, &v);
        if(s == 1) {
            a[la++] = v;
        }
        else {
            b[lb++] = v;
        }
    }
    sort(a, a + la); sort(b, b + lb);
    int m; scanf("%d", &m);
    while(m--) {
        int v; scanf("%d", &v);
        int ans1;
        if(a[la - 1] <= v) {
            ans1 = la;
        }
        else {
            ans1 = upper_bound(a, a + la, v) - a;
        }
        v = -v;
        int ans2;
        if(b[lb - 1] <= v) {
            ans2 = lb;
        }
        else {
            ans2 = upper_bound(b, b + lb, v) - b;
        }

        printf("%d\n", ans1 + ans2);

    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/chenzhenyu123456/article/details/63686581