AtCoder Beginner Contest 349

A题:

签到题,可以优化成sum为0,输入一个数后减去这个数进行输出。

inline void solve() {
	 int n; cin >> n;
	 int sum = 0;
	 for (int i = 1; i <= n - 1; i ++ ) {
	 	int x; cin >> x;
	 	sum += x;
	 }
	 cout << -sum << endl;
	 return;
}

B题: 

按题意模拟即可,用了cnt存次数,如果相同次数的不是两个(因为0个的没有存)那么就输出错误,否则Yes

inline void solve() {
	 string s; cin >> s;
	 map<char, int> p;
	 for (auto c : s) {
	 	p[c] ++;
	 }
	 bool ok = true;
	 map<int, int> cnt;
	 for (auto t : p) {
	 	cnt[t.second] ++;
	 }
	 for (auto t : cnt) {
	 	if (t.second != 2) ok = false;
	 }
	 if (ok) cout << "Yes\n";
	 else cout << "No\n";
	 return;
}

C题: 

还是模拟,重要的是子序列,用到了双指针的思想,如果相同则cnt进行移位。

inline void solve() {
	 string s, t;
	 cin >> s >> t;
	 int cnt = 0;
	 if (t[2] == 'X') {
	 	for (int i = 0; i < s.size(); i ++ ) {
	 		if (toupper(s[i]) == t[cnt]) {
	 			cnt ++;
	 		}
	 		if (cnt == 2) break;
	 	}
	 	if (cnt == 2) cout << "Yes\n";
	 	else cout << "No\n";
	 }else {
	 	for (int i = 0; i < s.size(); i ++ ) {
	 		if (toupper(s[i]) == t[cnt]) {
	 			cnt ++;
	 		}
	 		if (cnt == 3) break;
	 	}
	 	if (cnt == 3) cout << "Yes\n";
	 	else cout << "No\n";
	 }
	 return;
}

 D题:

模拟线段数的查询过程,

线段树最下面对应题目中的j == 0,然后逐级往上看,如果当前节点能够直接返回那么一定是最赚的,否则再进行查询。

vector<PLL> ans;
void query(ll l, ll r, ll L, ll R) {
	if (l >= L && r <= R) {
		ans.push_back({l, r + 1});
		return;
	}
	ll mid = l + r >> 1;
	if (L <= mid) query(l, mid, L, R);
	if (R > mid) query(mid + 1, r, L, R);
}
inline void solve() {
	 ll l, r; cin >> l >> r;
	 query(0, qmi(2, 60) - 1, l , r - 1);
	 sort(ans.begin(), ans.end());
	 cout << ans.size() << endl;
	 for (auto &[x, y] : ans) {
	 	cout << x  << ' ' << y << endl;
	 }
	 return;
}

E题: Weighted Tic-Tac-Toe  

两者都已最优方式放置,经典博弈论。

失败的条件是连成一条线或者总分比另外一个人低,这对应了f中的上面两个return情况(0代表先手获胜,1代表后手获胜)。

接着要枚举状态,如果当前位置没人放置,如果当前的人放了这个位置,之后获胜的还是这个人,那么就是必胜态,即f(now ^ 1, nxt) == now

否则则在dp中记录now ^ 1,并且返回now ^ 1

(期间用到记忆化搜索优化)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int dp[1 << 18];
bool vis[1 << 18];
int A[9];
int line[8] = {0b111, 0b111000, 0b111000000,
                0b1001001, 0b10010010, 0b100100100,
                0b100010001, 0b1010100};
bool get_bit(int x, int v) {
    return (x >> v) & 1;
}
int f(int now, array<int, 2> state) {
    for (int x : line) {
        if (x == (state[0] & x)) return 0;
        if (x == (state[1] & x)) return 1;
    }
    if ((state[0] | state[1]) == 511) {
        ll v = 0;
        for (int i = 0; i < 9; i ++ ) {
            if (get_bit(state[0], i)) {
                v += A[i];
            }else {
                v -= A[i];
            }
        }
        return v < 0;
    }
    if (vis[state[0] | (state[1] << 9)]) return dp[state[0] | (state[1] << 9)];
    vis[state[0] | (state[1] << 9)] = 1;
    dp[state[0] | state[1] << 9] = now;
    for (int i = 0; i < 9; i ++ ) {
        if (get_bit(state[0], i) || get_bit(state[1], i)) continue;
        array<int, 2> nxt = state;
        nxt[now] |= 1 << i;
        if (f(now ^ 1, nxt) == now) return now;
    }
    dp[state[0] | (state[1] << 9)] = now ^ 1;
    return now ^ 1;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    for (int i = 0; i < 9; i ++ ) cin >> A[i];
    if (!f(0, {0, 0})) {
        cout << "Takahashi\n";
    }else {
        cout << "Aoki\n";
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值