AtCoder Beginner Contest 155 简要题解

AtCoder Beginner Contest 155

A:签到失败,WA一次。

int main() {
    int a, b, c;
    cin >> a >> b >> c;
    if(a == b && b == c) cout << "No";
    else if(a == b || a == c || b == c) cout << "Yes";
    else cout << "No";
    return 0;
} 

B:签到失败乘2,这题又WA一次。

int main() {
    int n; scanf("%d", &n); bool ok = 1;
    while(n --) {
        int x; scanf("%d", &x);
        if(x % 2 == 0 && (x % 3 != 0 && x % 5 != 0)) {
            ok = 0;
        }
    }
    puts(ok ? "APPROVED" : "DENIED");
    return 0;
} 

C:直接开map。

string s[200010];
vector<string> vec;
map<string, int> Map;
int main() {
    int n; scanf("%d", &n); int ans = 0;
    for(int i = 1; i <= n; i ++) {
        cin >> s[i];
        ans = max(ans, ++ Map[s[i]]);
    }
    for(int i = 1; i <= n; i ++) {
        if(Map[s[i]] == ans) {
            Map[s[i]] = 0;
            vec.pb(s[i]);
        }
    }
    sort(vec.begin(), vec.end());
    for(auto s : vec) printf("%s\n", s.c_str());
    return 0;
} 

D:二分 + two-pointer,正负要讨论,注意不要使用实数运算求floor和ceil。代码非常丑。


const int N = 2e5 + 10;
int n, rpos, a[N]; ll k;
ll C(ll n) { return n * (n - 1) / 2; }
ll fl(ll a, ll b) {
    bool f = (a < 0) ^ (b < 0);
    if(a < 0) a = -a;
    if(b < 0) b = -b;
    return f ? - ( a / b + 1 ) : a / b;
}
ll cl(ll a, ll b) {
    bool f = (a < 0) ^ (b < 0);
    if(a < 0) a = -a;
    if(b < 0) b = -b;
    return f ? - ( a / b ) : (a + b - 1) / b;
}
int main() {
    scanf("%d%lld", &n, &k);
    for(int i = 1; i <= n; i ++) scanf("%d", a + i);
    sort(a + 1, a + n + 1);
    ll l = 0, r = 0, z = 0, L = 0, R = 0, Z = 0;
    for(int i = 1; i <= n; i ++) z += a[i] == 0;
    for(int i = 1; i <= n; i ++) l += a[i] < 0;
    for(int i = 1; i <= n; i ++) r += a[i] > 0;
    L = l * r; R = C(l) + C(r); Z = C(n) - L - R;
    rpos = n + 1;
    for(int i = 1; i <= n; i ++) if(a[i] > 0) {
        rpos = i; break ;
    }
    if(k <= L) {
        ll ql = -1e18, qr = -1, mid, ans = -233;
        while(ql <= qr) {
            mid = (ql + qr) >> 1;
            ll sum = 0, now = r, cur = rpos;
            for(int i = 1; i <= n && a[i] < 0; i ++) {
                ll up = mid % a[i] == 0 ? mid / a[i] + 1 : cl(mid, a[i]);
                while(now && a[cur] < up) cur ++, now --;
                sum += now;
            }
            if(sum < k) ql = (ans = mid) + 1;
            else qr = mid - 1;
        }
        printf("%lld\n", ans);
    } else if(k <= L + Z) {
        puts("0");
    } else {
        k -= L + Z;
        ll ql = 1, qr = 1e18, mid, ans = -233;
        while(ql <= qr) {
            mid = (ql + qr) >> 1;
            ll sum = 0, now = r, cur = n;
            for(int i = rpos; i <= n; i ++) {
                ll up = mid % a[i] == 0 ? mid / a[i] - 1 : fl(mid, a[i]);
                while(now && a[cur] > up) cur --, now --;
                sum += cur >= i ? now - 1 : now;
            }
            now = l; cur = 1;
            for(int i = n; i >= 1; i --) if(a[i] < 0) {
                ll up = mid % a[i] == 0 ? mid / a[i] + 1 : cl(mid, a[i]);
                while(now && a[cur] < up) cur ++, now --;
                sum += cur <= i ? now - 1 : now;
            }
            sum >>= 1;
            if(sum < k) ql = (ans = mid) + 1;
            else qr = mid - 1;
        }
        printf("%lld\n", ans);
    }
    return 0;
} 

E:dp[i][0/1]表示前i位,第i位要不要借给下一位,最小代价。

char s[N];
int dp[N][2];
bool ok(int x) { return x >= 0 && x < 10; }
int main() {
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    dp[0][1] = 1; dp[0][0] = 0;
    for(int i = 1; i <= n; i ++) {
        dp[i][0] = dp[i][1] = 1e9;
        int x = s[i] - '0';
        for(int j = 0; j < 10; j ++) {
            if(ok(10 + j - x)) dp[i][0] = min(dp[i][0], dp[i - 1][1] + j + (10 + j - x));
            if(ok(j - x)) dp[i][0] = min(dp[i][0], dp[i - 1][0] + j + (j - x));
            if(ok(10 + (j - 1) - x)) dp[i][1] = min(dp[i][1], dp[i - 1][1] + j + (10 + j - 1 - x));
            if(ok(j - 1 - x)) dp[i][1] = min(dp[i][1], dp[i - 1][0] + j + (j - 1 - x));
        }
    }
    printf("%d\n", dp[n][0]);
    return 0;
} 

F:差分,然后区间xor变成两点同时xor。所有l和r+1连边建图,问题转换为选若干条边,一条边被选两个端点就xor上1。

对于每个连通块dfs,如果当前子树的根状态为1就选这条边,否则不选,这样若不合法只可能根不合法。若根不合法,显然无解,因为若要选非dfs树边,一定会出现其他不合法点。

const int N = 2e5 + 10;

struct node {
    int a, b;
} x[N], t[N];
int n, q, b[N];
bool ans[N], st[N], vis[N];
vector<pii> G[N];
int get(int u) { return lower_bound(b + 1, b + n + 1, u) - b; }
int getl(int u) { return upper_bound(b + 1, b + n + 1, u) - b - 1; }
void link(int u, int v, int w) { G[u].pb(pii(v, w)); G[v].pb(pii(u, w)); }
int dfs(int u) {
    vis[u] = 1; int x = st[u];
    for(auto v : G[u]) if(!vis[v.fs]) {
        if(dfs(v.fs)) { ans[v.sc] = 1; x ^= 1; }
    }
    return x;
}
int main() {
    scanf("%d%d", &n, &q);
    for(int i = 1; i <= n; i ++) { scanf("%d%d", &x[i].a, &x[i].b); b[i] = x[i].a; }
    for(int i = 1; i <= q; i ++) scanf("%d%d", &t[i].a, &t[i].b);
    sort(b + 1, b + n + 1);
    for(int i = 1; i <= n; i ++) { x[i].a = get(x[i].a); st[x[i].a] = x[i].b; }
    for(int i = n + 1; i >= 1; i --) st[i] ^= st[i - 1];
    for(int i = 1; i <= q; i ++) link(get(t[i].a), 1 + getl(t[i].b), i);
    for(int i = 1; i <= n + 1; i ++) if(!vis[i]) {
        if(dfs(i)) { puts("-1"); return 0; }
    }
    int r = 0;
    for(int i = 1; i <= q; i ++) r += ans[i];
    printf("%d\n", r);
    for(int i = 1; i <= q; i ++) if(ans[i]) printf("%d ", i);
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/hongzy/p/12319488.html
今日推荐