Codeforces Round #360 (Div. 2)

A
最大连续的存在0字符子串个数。

#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
    int n, d;
    while(scanf("%d%d", &n, &d) != EOF) {
        int l = 0, ans = 0;
        for(int i = 0; i < d; i++) {
            char str[110];
            scanf("%s", str);
            bool flag = false;
            for(int j = 0; j < n; j++) {
                if(str[j] == '0') {
                    flag = true; break;
                }
            }
            if(flag) {
                ans = max(ans, i - l + 1);
            }
            else {
                l = i+1;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

B

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main()
{
    string a;
    while(cin >> a) {
        cout << a;
        reverse(a.begin(), a.end());
        cout << a << endl;
    }
    return 0;
}

C
题意::给定一个图,可能非联通,让你将它划分为两个集合。说白了就是——划分成二分图。
思路:先DFS,然后黑白染色。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN = 1e5 + 10;
vector<int> G[MAXN];
int color[MAXN], in[MAXN];
bool judge(int u) {
    for(int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if(color[u] == color[v]) return false;
        if(!color[v]) {
            color[v] = 3 - color[u];
            if(!judge(v)) return false;
        }
    }
    return true;
}
int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF) {
        for(int i = 1; i <= n; i++) {
            G[i].clear(); color[i] = in[i] = 0;
        }
        for(int i = 0; i < m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
            in[u]++; in[v]++;
        }
        bool flag = true;
        for(int i = 1; i <= n; i++) {
            if(in[i] && color[i] == 0) {
                color[i] = 1;
                flag &= judge(i);
                if(!flag) break;
            }
        }
        if(!flag) {
            printf("-1\n");
        }
        else {
            int cnt1 = 0, cnt2 = 0;
            for(int i = 1; i <= n; i++) {
                cnt1 += color[i] == 1;
                cnt2 += color[i] == 2;
            }
            printf("%d\n", cnt1);
            int cnt = 0;
            for(int i = 1; i <= n; i++) {
                if(color[i] == 1) {
                    if(cnt > 0) printf(" ");
                    printf("%d", i);
                    cnt++;
                }
            }
            printf("\n%d\n", cnt2);
            cnt = 0;
            for(int i = 1; i <= n; i++) {
                if(color[i] == 2) {
                    if(cnt > 0) printf(" ");
                    printf("%d", i);
                    cnt++;
                }
            }
            printf("\n");
        }
    }
    return 0;
}

D

题意比较晦涩吧,总之最后就是判断lcm(a[1],…,a[n]) % k == 0。
两种方法
一、每次记录v最大的质因子,这样求出v的质因子时间复杂度是log(v),下面用快速幂求一次就好了。
二、比较神奇,lcm(gcd(a[1], k),…,gcd(a[n], k)) == k。

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1e6 + 10;
LL pow_mod(LL a, LL n, LL k) {
    LL ans = 1;
    while(n) {
        if(n & 1) {
            ans = ans * a % k;
        }
        a = a * a % k;
        n >>= 1;
    }
    return ans;
}
int cnt[MAXN];
int pre[MAXN];
int main()
{
    for(int i = 2; i <= 1000000; i++) {
        if(!pre[i]) {
            pre[i] = i;
            for(int j = 2 * i; j <= 1000000; j += i) {
                pre[j] = i;
            }
        }
    }
    int n, k;
    while(scanf("%d%d", &n, &k) != EOF) {
        memset(cnt, 0, sizeof(cnt));
        int Max = 0;
        for(int i = 1; i <= n; i++) {
            int v; scanf("%d", &v); Max = max(Max, v);
            while(v > 1) {
                int p = pre[v]; int num = 0;
                while(v % p == 0) {
                    v /= p;
                    num++;
                }
                cnt[p] = max(cnt[p], num);
            }
            if(v > 1) {
                cnt[v] = max(cnt[v], 1);
            }
        }
        LL ans = 1LL % k;
        for(int i = 2; i <= Max; i++) {
            if(cnt[i]) {
                ans = ans * pow_mod(i, cnt[i], k) % k;
            }
        }
        printf(ans == 0 ? "Yes\n" : "No\n");
    }
    return 0;
}

E
题意:给定n个数,你需要选出某个集合使集合内元素之和等于k。问所有合法集合可以得到的数(可以让集合内元素相加)。

思路:明显的dp,而且数据范围正好是时间复杂度可以承受的。
dp[i][j][k] 表示前i个数(包括第i个数)选出某个集合元素之和为k且该集合可以得到j。合法为true,反之false。
这样时间复杂度是 O(nkk)

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <set>
#include <cstring>
using namespace std;
bool dp[2][501][501];
int a[501];
int main()
{
    int n, sum;
    while(scanf("%d%d", &n, &sum) != EOF) {
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        memset(dp, false, sizeof(dp));
        bool id = 0;
        dp[id][a[1]][0] = dp[id][a[1]][a[1]] = true;
        for(int i = 1; i < n; i++) {
            dp[!id][a[i+1]][a[i+1]] = true;
            dp[!id][a[i+1]][0] = true;
            for(int j = 0; j <= 500; j++) {
                for(int k = 0; k <= 500; k++) {
                    if(dp[id][j][k]) {
                        dp[!id][j][k] = true;
                        if(j + a[i+1] <= 500) {
                            dp[!id][j + a[i+1]][k] = true;
                            if(k + a[i+1] <= 500) {
                                dp[!id][j + a[i+1]][k + a[i+1]] = true;
                            }
                        }
                    }
                }
            }
            id = !id;
        }
        int cnt = 0;
        for(int i = 0; i <= 500; i++) {
            if(dp[id][sum][i]) {
                cnt++;
            }
        }
        printf("%d\n", cnt); int num = 1;
        for(int i = 0; i <= 500; i++) {
            if(dp[id][sum][i]) {
                if(num > 1) printf(" ");
                printf("%d", i);
                num++;
            }
        }
        if(cnt) printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值