AtCoder Beginner Contest 295

1|0A - Probably English


#include <bits/stdc++.h> using namespace std; int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int main() { set<string> st; st.insert("and"); st.insert("not"); st.insert("that"); st.insert("the"); st.insert("you"); int n; cin >> n; string s; for( ; n ; n -- ){ cin >> s; if( st.count(s) ) cout << "Yes" , exit(0); } cout << "No"; return 0; }

2|0B - Bombs


#include <bits/stdc++.h> using namespace std; int f[25][25] ; int main() { int n , m; cin >> n >> m; vector<int> x , y , b; for( int i = 1 ; i <= n ; i ++ ){ string s; cin >> s; for( int j = 1 ; j <= m ; j ++ ){ if( s[j-1] == '#' ) f[i][j] = 1; else if( s[j-1] >= '1' && s[j-1] <= '9' ) x.push_back(i) , y.push_back(j) , b.push_back( s[j-1] - '0' ); } } for( int i = 1 ; i <= n ; i ++ ){ for( int j = 1 ; j <= m ; j ++ ){ if( f[i][j] == 0 ) continue; for( int k = 0 ; k < x.size() ; k ++ ){ if( abs( i - x[k] ) + abs( j - y[k] ) <= b[k] ){ f[i][j] = 0; break; } } } } for( int i = 1 ; i <= n ; i ++ ){ for( int j = 1 ; j <= m ; j ++ ) cout << ".#"[ f[i][j] ]; cout << "\n"; } return 0; }

3|0C - Socks


#include <bits/stdc++.h> using namespace std; int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int main() { int n = read(); map<int,int> mp; for( int x ; n ; n -- ) x = read() , mp[x] ++; int res = 0; for( auto [k,v] : mp ) res += v/2; cout << res; return 0; }

4|0D - Three Days Ago


如果一个子区间内所有的数都只出现偶数次的话,就一定 happy 的。

我们用一个十位的二进制来表示前缀中每个字母出现了奇数次还是偶数次。这个实际上可以用前缀异或和来维护。

那么我们只需要统计这个十位二进数每种出现了多少次,然后对每一种求一个Cn2即可

#include <bits/stdc++.h> using namespace std; #define int long long int32_t main() { ios::sync_with_stdio(false) , cin.tie(nullptr) , cout.tie(nullptr); string s; cin >> s; int t = 0; bitset<10> T; map<int,int> cnt; cnt[t] ++; for( auto i : s ){ t ^= 1 << ( i - '0' ); cnt[t] ++; } int res = 0; for( auto [ k , v ] : cnt ) res += v * ( v - 1 ) / 2 ; cout << res; return 0; }

5|0E - Kth Number


设第k大的数字是x则题目要求的就是EX=i=1ni×P(x=i)

EX=1P(x=1)+2P(x=2)+nP(x=n)=i=1nP(x=i)+i=2nP(x=i)++i=nnP(x=i)=P(x1)+P(x2)++P(xn)=i=1nP(x>i)

这样转换的好处就是算的时候比较方便,我们直接枚举 i的值,然后统计数列中的值即可。

如果已经有大于等于nk+1个数大于等于i,则概率为1,因为不用操作第k个数也大于i

如果已经有大于k个数小于i,则概率为 0。

如果都不满足的话,就可以通过操作是条件满足,设b表示当前大于i的个数,p=mi+1m表示把一个 0 变成大于i的概率,cnt0表示0的个数,概率是j=nk+1bcnt0Ccnt0jpj(1p)cnt0j

把所有的概率求和就是答案

#include <bits/stdc++.h> using namespace std; #define int long long const int mod = 998244353; int power(int x, int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod, y >>= 1; } return ans; } int inv(int x) { return power(x, mod - 2) % mod; } const int N = 2005; int fact[N], invFact[N]; int A(int x, int y) { // x 中选 y 排序 return fact[x] * invFact[x - y] % mod; } int C(int x, int y) { // x 中选 y 个 return fact[x] * invFact[x - y] % mod * invFact[y] % mod; } void init() { fact[0] = 1, invFact[0] = inv(1); for (int i = 1; i < N; i++) fact[i] = fact[i - 1] * i % mod, invFact[i] = inv(fact[i]); } int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int32_t main() { init(); int n = read(), m = read(), k = read(), res = 0; vector<int> cnt(m + 1), a(m + 1), b(m + 1); for (int x, i = 1; i <= n; i++) x = read(), cnt[x]++; b[m] = cnt[m]; for (int i = 1; i <= m; i++) a[i] = a[i - 1] + cnt[i]; for (int i = m - 1; i >= 1; i--) b[i] = b[i + 1] + cnt[i]; for (int i = 1, p, q; i <= m; i++) { if (a[i - 1] > k) continue; if (b[i] >= n - k + 1) { res = (res + 1) % mod; continue; } p = (m - i + 1) * inv(m) % mod, q = ( 1 - p + mod ) % mod; for (int j = n - k + 1 - b[i]; j <= cnt[0]; j++) res = (res + C(cnt[0], j) * power(p, j) % mod * power(q, cnt[0] - j) % mod) % mod; } cout << res; return 0; }

6|0G - Minimum Reachable City


当加边(u,v)的时候保证了(v,u)已经联通了,此时有两种情况如果(u,v)已经联通了,此时加边对结果实际上是没有影响的,可以忽略。另一种情况是不联通,那么此时等价于将(v,u)之间的路径全部建一遍反向边。

所以这个问题就可以用并查集来维护联通性,同时保证根节点是该联通块中最小的一个,所以要注意加边和并两个集合的方向。

在一开始,我们就只是存一下反向边,当需要加(u,v)就从u开始一路加反向边直到u,v联通,回答的时候直接回答该点所在联通快递根节点即可。

#include<bits/stdc++.h> using namespace std; int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } class dsu{ private: vector<int> fa; public: dsu( int n = 1 ){ fa = vector<int>( n+1 , -1 ) , fa[0] = 0; } int getfa( int x ){ if( fa[x] < 0 ) return x; return fa[x] = getfa( fa[x] ); } void merge( int x , int y ){ x = getfa(x) , y = getfa(y); if( x == y ) return ; fa[x] = y; } bool check( int x , int y ){ x = getfa(x) , y = getfa(y); return ( x == y ); } }; int32_t main() { int n = read(); vector<int> p(n+1); p[1] = 1; for( int i = 2 ; i <= n ; i ++ ) p[i] = read(); dsu d(n); for( int q = read() , op , x , y ; q ; q -- ){ op = read(); if( op == 1 ){ x = read() , y = read(); while( !d.check( x , y ) ){ x = d.getfa(x); d.merge( x , p[x] ); } }else x = read() , printf("%d\n" , d.getfa(x) ); } return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/17266778.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(125)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示