Codeforces Round 347 div1 abc 662BD 663A

Codeforces Round 347 div1
通过数: 0
A:
/*
就是整数划分之类问题
注意几个坑点
负数不是都取-1,可能取n来满足过多正数的条件

自己的解法是在选取正数都取1(负数都取-1),负数(正数)需要满足等式的最大值。
这样正数(负数类似)可以分成三个部分
一是值为n的部分,一是中间值部分,一是值为1的部分
遗憾的是赛中中间值部分值大于n时未作处理……

标程是利用合法性进行暴力求解的方法,比这个好~

*/

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e4 + 5;
char str[MAXN];
int main()
{
    while(fgets(str, MAXN, stdin)) {
        int t1 = str[0] == '-' ? 0 : 1, t2 = 0;
        int flag = 0;
        int n = 0;
        for(int i = 0 ; i < strlen(str) ; i++) {
            if(flag) {
                if(str[i] >= '0' && str[i] <= '9') n = n * 10 + str[i] - '0';
            }
            else {
                if(str[i] == '=') flag = 1;
                else if(str[i] == '-') t2++;
                else if(str[i] == '+') t1++;
            }
        }
        if(t1 * n < t2 + n || t1 > t2 * n + n) puts("Impossible");
        else {
            puts("Possible");
            int sign = 1;
            int cnt1, cnt2;
            cnt1 = 0; cnt2 = 0;
            int orgn = max(n + t2, t1);
            int num1 = 0;
            if(n != 1) {
                while((num1 + 1) * n + n + t1 - num1 - 2 <= orgn) num1++;
            }
            int pre1 = n;
            int last1 = 1;
            int mid1 = orgn - num1 * pre1 - (t1 - num1 - 1);
            while(num1 >= 0 && mid1 <= 0) num1--, mid1 += n - 1;
            while(mid1 > n) mid1 -= n - 1, num1++;
            int num2 = 0;
            if(n != 1) {
                while(pre1 * num1 + mid1 + (t1 - num1 - 1) - ((n * (num2 + 1) + n + t2 - num2 - 2))  >= n) {
//                    printf("f1 = %d, f2 = %d\n", pre1 * num1 + mid1 + (t1 - num1 - 1), (n * (num2 + 1) + n + t2 - num2 - 2));
                    num2++;
                }
            }
            int pre2 = n;
            int last2 = 1;
            int mid2 = n + num2 * pre2 + (t2 - num2 - 1) - (pre1 * num1 + mid1 + (t1 - num1 - 1));
            mid2 = -mid2;
//            printf("pre2 = %d, mid2 = %d\n", pre2, mid2);
//            printf("mid1 = %d\n", mid1);
//            printf("num1 = %d, num2 = %d\n", num1, num2);
            while(num2 >= 0 && mid2 <= 0) num2--, mid2 += n - 1;
            while(mid2 > n) num2++, mid2 -= n - 1;
//            printf("num1 = %d, num2 = %d\n", num1, num2);
//            printf("num1 = %d, pre = %d, mid = %d, last = %d\n", num1, pre, mid, last);
            for(int i = 0 ; i < strlen(str) ; i++) {
                if(str[i] == '?') {
                    if(sign == 1) {
                        if(cnt1 < num1) printf("%d", pre1);
                        else if(cnt1 == num1) printf("%d", mid1);
                        else printf("%d", last1);
                        cnt1++;
                    }
                    else  {
                        if(cnt2 < num2) printf("%d", pre2);
                        else if(cnt2 == num2) printf("%d", mid2);
                        else printf("%d", last2);
                        cnt2++;
                    }
                }
                else {
                    if(str[i] == '-') sign = -1;
                    if(str[i] == '+') sign = 1;
                    printf("%c", str[i]);
                }
            }
            puts("");
        }
    }
    return 0;
}
/*
? + ? + ? + ? - ? = 2
*/

B:
/*
首先明白题意是后几位未出现数字,也就是会有IAO’09这种情况出现
然后发现两位数在一个区间长度为100的连续区间内,三位数在长度1000的连续区间内
且所有区间按区间大小从小到大排列
对于一个k位数,它的最小值是1989+(10^(k-1) + 10^(k-2) + … + 10)
因为尾k位数是确定的,所以它每次只在最前面加上10^k这个数,直到大于等于最小值
*/

#include <bits/stdc++.h>
using namespace std;
#define LL long long
char str[20];
int main()
{
    int n;
    while(scanf("%d", &n) != EOF) {
        while(n--) {
            scanf("%s", str);
            int k = strlen(str + 4);
            LL ans = atoi(str + 4);
            int F = 0;
            int ten = 10;
            for(int i = 1 ; i < k ; i++) {
                F += ten; ten *= 10;
            }
            while(ans < F + 1989) ans += ten;
            cout << ans << endl;
        }
    }
    return 0;
}

C:
/*
首先确定是要留下哪一种颜色
然后对每个连通块,确定一点一定要取之后,可以根据边颜色的合法性判断下一个未访问点是否需要使用
以及如果下一个点是已访问点,需要进行合法性判断
然后每个连通块取当前假设要取的点和不取点里的最小值,可以用最小二分染色理解。
*/

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef pair<int,int> pii;
const int MAXN = 1e5 + 5;
int color[MAXN], tcolor[MAXN];
int vis[MAXN], vis2[MAXN];
int use[MAXN];
int n, m;
vector<pii> e[MAXN];
pii bfs(int st, int c)
{
//    printf("st = %d\n", st);
    int tot = 1;
    queue<int> que;
    vis[st] = 1; use[st] = 1;
    for(auto p : e[st]) {
        vis[p.fi] = 1; que.push(p.fi);
        if(color[p.se] == c) use[p.fi] = 1;
        else use[p.fi] = 0;
    }
    int res = 1;
    while(!que.empty()) {
        tot++;
        int u = que.front(); que.pop();
        if(use[u]) res++;
        for(auto p : e[u]) {
            int v = p.fi, mark = p.se;
            if(vis[p.fi] == 0) {
                if(use[u] == (color[p.se] == c)) use[p.fi] = 1;
                vis[p.fi] = 1;
                que.push(p.fi);
            }
            else if((use[u] + use[p.fi]) % 2 == (color[p.se] == c)) {
//                printf("u = %d, p.fi = %d, c = %d\n", u, p.fi, c);
//                printf("use[u] = %d, use[p.fi] = %d, color[p.se] = %d\n", use[u], use[p.fi], color[p.se]);
//                system("pause");
                return mp(tot, -1);
            }
        }
    }
    if(tot - res < res) {
        que.push(st);
        vis2[st] = 1;
        while(!que.empty()) {
            int u = que.front(); que.pop();
            use[u] = use[u] == 1 ? 0 : 1;
            for(auto p : e[u]) {
                if(vis2[p.fi] == 0) que.push(p.fi), vis2[p.fi] = 1;
            }
        }
    }
    return mp(tot, res);
}
int solve(int c)
{
    memset(vis, 0, sizeof vis);
    memset(vis2, 0, sizeof vis2);
    memset(use, 0, sizeof use);
    int res = 0;
    for(int i = 1 ; i <= n ; i++) {
        if(vis[i] == 0) {
            pii temp = bfs(i, c);
            if(temp.se == -1) return -1;
            else {
//                printf("temp.fi = %d, temp.se = %d\n", temp.fi, temp.se);
                res += min(temp.fi - temp.se, temp.se);
            }
        }
    }
    return res;
}
int use1[MAXN], use2[MAXN];
int main()
{
    while(scanf("%d%d", &n, &m) != EOF) {
        for(int i = 1 ; i <= n ; i++) e[i].clear();
        for(int i = 1 ; i <= m ; i++) {
            char str[10];
            int u, v; scanf("%d%d%s", &u, &v, str);
            e[u].pb(mp(v, i));  e[v].pb(mp(u, i));
            if(str[0] == 'R') color[i] = 1;
            else color[i] = -1;
        }

        int ans = n + 1;
        int t1 = solve(1);
        if(t1 != -1) ans = min(ans, t1);
        memcpy(use1, use, sizeof use);
        int t2 = solve(-1);
        if(t2 != -1) ans = min(ans, t2);
        memcpy(use2, use, sizeof use);
//        printf("t1 = %d, t2 = %d\n", t1, t2);
        if(ans == n + 1) puts("-1");
        else {
            printf("%d\n", ans);
            if(ans == t1) {
                int f = 1;
                for(int i = 1 ; i <= n ; i++) {
                    if(use1[i] == 0) continue;
                    if(f) f = 0;
                    else printf(" ");
                    printf("%d", i);
                }
                puts("");
            }
            else {
                int f = 1;
                for(int i = 1 ; i <= n ; i++) {
                    if(use2[i] == 0) continue;
                    if(f) f = 0;
                    else printf(" ");
                    printf("%d", i);
                }
                puts("");
            }
        }

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值