AtCoder Beginner Contest 246 题解
AtCoder Beginner Contest 246 Solution
更好的阅读体验戳此进入
题面链接
题面 Luogu 链接
A - Four Points
题面
给定矩形三个点坐标,求另一个点的坐标。
Solution
显然四个点横纵坐标分别两两相等,三个横坐标异或,三个纵坐标异或即可。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template<typename T = int>
inline T read(void);
int main(){
int x1 = read(), y1 = read(), x2 = read(), y2 = read(), x3 = read(), y3 = read();
printf("%d %d\n", x1 ^ x2 ^ x3, y1 ^ y2 ^ y3);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
B - Get Closer
题面
给定一个向量的坐标表示,求同向模长为 $ 1 $ 的向量坐标。
Solution
语法题没营养,为了凑齐一套题去写的。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template<typename T = int>
inline T read(void);
int main(){
int x = read(), y = read();
ld base = sqrtl((ld)x * x + (ld)y * y);
printf("%.8Lf %.8Lf\n", (ld)x / base, (ld)y / base);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
C - Coupon
题面
$ n $ 个物品第 $ i $ 个价格为 $ a_i $,有 $ k $ 张 $ x $ 元优惠券,可以叠加,但不能分裂开使用,求全部购买的最少花费。
Solution
对于所有 $ a_i \ge x $ 一直使用优惠券直到 $ a_i \lt x $,然后降序排序用剩余的 $ k $ 个券把前 $ k $ 个抵消,后面的求和即为答案。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template<typename T = int>
inline T read(void);
int a[210000];
int main(){
int N = read(), K = read(), X = read();
for(int i = 1; i <= N; ++i){a[i] = read();while(K && a[i] >= X)--K, a[i] -= X;}
sort(a + 1, a + N + 1, greater < int >());
ll ans(0);
for(int i = K + 1; i <= N; ++i)ans += a[i];
printf("%lld\n", ans);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
D - 2-variable Function
题面
存在函数 $ f(a, b) = a^3 + a^2b + ab^2 + b^3 $,要求 $ a, b \ge 0 $,给定 $ n $,求最小的 $ f(a, b) $ 满足 $ f(a, b) \ge n \(。\) n \le 10^{18} $。
Solution
显然 $ a, b $ 的范围不超过 $ 10^6 $,则可以枚举 $ a $,二分 $ b $,取最小值即可。
对于二分 $ b $ 的单调性证明,可以考虑固定 $ a $ 为参数,则有函数 $ f(b) = b^3 + ab^2 + a^2b + a^3 $,三次函数不好操作,所以考虑求导,显然 $ f'(b) = 3b^2 + 2ab + a^2 $,因为 $ a, b $ 非负,所以显然导函数 $ f'(b) \ge 0 $,所以范围内函数取值单调递增,于是可以二分。
或者不进行二分,根据单调性,显然 $ a $ 减小时 $ b $ 不会比上次更大,所以写个双指针枚举,$ a $ 升序,$ b $ 降序,小于 $ n $ 时直接 break 即可。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template<typename T = int>
inline T read(void);
ll Func(int a, int b){
return (ll)a * a * a + (ll)a * a * b + (ll) a * b * b + (ll)b * b * b;
}
int main(){
ll N = read<ll>();
ll mn(LLONG_MAX);
for(int x = 0; x <= (int)1e6; ++x){
int l = 0, r = (int)1e6;
ll cur(-1);
while(l <= r){
int mid = (l + r) >> 1;
ll tmp = Func(x, mid);
if(tmp >= N)cur = tmp, r = mid - 1;
else l = mid + 1;
}
mn = min(mn, cur);
}printf("%lld\n", mn);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
E - Bishop 2
题面
给定有障碍的网格图,. 为空地,# 为障碍。给定起点终点,每次移动仅可以斜向走任意长度,问从起点到终点的最少移动次数,可能无解,无解输出 -1。
Solution
BFS 较为显然,因为时限 6000ms,只要写的不太丑直接搜也能过。对于本题,使用 01BFS 较为显然。我们在宽搜每次搜一步且距离仅为 $ 1 $,并记录上一步的方向,如果同向则认为走了一个 $ 0 $ 边,异向则为 $ 1 $ 边,开个双端队列,同向插到前面,反之插到后面,按照正常宽搜每次取队头扩展即可。
需要注意对于 01BFS 时,我们判断是否走过和是否为答案的时候,需要在从队头取元素的时候判断,而不是在扩展的时候判断。因为如果在某一次由 $ 1 $ 扩展的时候如果直接把 $ vis $ 设为 $ \texttt{true} $,但是这可能会导致后面从 $ 0 $ 扩展的,本应能插在队列中比这个更前面的更优的无法转移,使答案更劣。同时我们也需要考虑到不同方向的时候扩展也是不同,所以 $ vis $ 中也要考虑到方向这一维。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define CHK(x, y) (x >= 1 && x <= N && y >= 1 && y <= N && !mp[x][y])
template<typename T = int>
inline T read(void);
int N;
int dx[10] = {0, -1, -1, 1, 1};
int dy[10] = {0, -1, 1, -1, 1};
int vis[1600][1600][5];
bool mp[1600][1600];
struct Status{
int x, y;
int dir;//direction 1, 2, 3, 4
int dist;
}S, T;
void Init(void){
char c = getchar();
for(int i = 1; i <= N; ++i)for(int j = 1; j <= N; ++j){
while(c != '.' && c != '#')c = getchar();
mp[i][j] = c == '.' ? false : true;
c = getchar();
}
}
void bfs(void){
deque < Status > dq;
dq.push_back(S);
while(!dq.empty()){
auto tp = dq.front(); dq.pop_front();
if(vis[tp.x][tp.y][tp.dir])continue;
vis[tp.x][tp.y][tp.dir] = true;
if(tp.x == T.x && tp.y == T.y)
printf("%d\n", tp.dist), exit(0);
// printf("Current pos (%d, %d): dis = %d, dir = %d\n", tp.x, tp.y, tp.dist, tp.dir);
for(int i = 1; i <= 4; ++i){
int tx = tp.x + dx[i], ty = tp.y + dy[i];
if(!CHK(tx, ty))continue;
if(i == tp.dir)dq.push_front(Status{tx, ty, i, tp.dist});
else dq.push_back(Status{tx, ty, i, tp.dist + 1});
}
}printf("-1\n");
}
int main(){
// freopen("test_11.txt", "r", stdin);
N = read();
int x = read(), y = read(); S = Status{x, y, 0, 0};
x = read(), y = read(); T = Status{x, y, 0, 0};
Init();
bfs();
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
F - typewriter
题面
给定 $ n $ 个字符串,字符集为小写字母,可以任意选择一个字符串,作为字符库,然后(可多次选择同一字符)任意组成长度为 $ l $ 的字符串,求一共能形成多少种长度为 $ l $ 的字符串。
Solution
容斥较为显然,显然最终答案也就是,用任意一个字符集形成的字符串减去任意两个的加上任意三个...于是我们考虑令全集为 $ S = 2^n - 1 $ 然后对其进行枚举子集,二进制第 $ i $ 位为 $ 1 $ 或 $ 0 $ 代表是否考虑这个数,所以枚举的时候直接 __builtin_popcount() 算一下个数,奇数代表加,反之减。然后对于每一个字符串,因为字符集较小,也用一个 int 的二进制表示是否存在对应的字符,然后把需要的字符串都与起来,设数量为 $ \xi $,则此次运算的字符集大小则为 $ \xi $,所以此次答案为 $ \xi^l $,加减考虑好即可。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define MOD 998244353
template<typename T = int>
inline T read(void);
int N, L;
int str[20];
int readStr(void){
int ret(0);
char c = getchar();
while(!islower(c))c = getchar();
vector < int > val;
while(islower(c)){
ret |= 1 << (c - 'a');
c = getchar();
}return ret;
}
ll qpow(ll a, ll b){
ll ret(1), mul(a);
while(b){
if(b & 1)ret = ret * mul % MOD;
b >>= 1;
mul = mul * mul % MOD;
}return ret;
}
int main(){
N = read(), L = read();
ll ans(0);
for(int i = 1; i <= N; ++i)str[i] = readStr();
// for(int i = 1; i <= N; ++i)
// cout << bitset < 32 > (str[i]) << endl;
int Smx = (1 << N) - 1;
// cout << "Smx" << bitset < 32 > (Smx) << endl;
for(int S = Smx; S; S = (S - 1) & Smx){
// cout << "S:" << bitset < 32 > (S) << endl;
int cnt = __builtin_popcount(S);
int tot((1 << 26) - 1);
// cout << "tot_pre:" << bitset < 32 > (S) << endl;
for(int i = 0; i <= N - 1; ++i)
if((1 << i) & S)tot &= str[i + 1];
// cout << "tot:" << bitset < 32 > (tot) << endl;
ans = (ans + qpow(__builtin_popcount(tot), L) * ((cnt & 1) ? 1 : -1) + MOD) % MOD;
}
printf("%lld\n", ans);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
G - Game on Tree 3
题面
类似于 LG-P3554 [POI2013]LUK-Triumphal arch,给定一棵树,有点权,B 初始在 $ 1 $,每轮 A 选择一个点将权值变为 $ 0 $,然后 B 移动一次,B 可在任意时刻停止游戏然后获得所在点上的权值的得分,两人均采取最优策略那么最终 B 最少会拿到多少的得分。
Solution
与 POI2013 基本相同,对于本题依然考虑二分答案,对于当前的答案 $ k $,认为大于 $ k $ 的贡献为 $ 1 $,小于等于的为 $ 0 $,于是显然有 dp,令 $ dp(i) $ 表示在 $ i $ 节点上时需要额外多少次的变为 $ 0 $ 的操作,显然有转移 $ dp(i) = \max(\sum_{j \in son(i)} dp(j) - 1, 0) + \left[ v(i) \gt k \right] $,最后判断一下根节点 $ 1 $ 为 $ 0 $ 则合法,反之不合法。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
template<typename T = int>
inline T read(void);
int N;
struct Edge{
Edge* nxt;
int to;
OPNEW;
}ed[410000];
ROPNEW(ed);
Edge* head[210000];
int val[210000];
int mnval(INT_MAX), mxval(-1);
int f[210000];
void dfs(int k, int p = 1, int fa = 0){
for(auto i = head[p]; i; i = i->nxt){
if(SON == fa)continue;
dfs(k, SON, p);
f[p] += f[SON];
}
f[p] -= 1;
f[p] = max(0, f[p]);
f[p] += val[p] > k ? 1 : 0;
}
bool Check(int K){
memset(f, 0, sizeof(f));
dfs(K);
return f[1] == 0;
}
int main(){
N = read();
for(int i = 2; i <= N; ++i)val[i] = read(), mxval = max(mxval, val[i]);
for(int i = 1; i <= N - 1; ++i){
int s = read(), t = read();
head[s] = new Edge{head[s], t};
head[t] = new Edge{head[t], s};
if(s == 1)mnval = min(mnval, val[t]);
if(t == 1)mnval = min(mnval, val[s]);
}if(!head[1]->nxt)mnval = 0;
int l = mnval, r = mxval;
int ans(-1);
while(l <= r){
int mid = (l + r) >> 1;
Check(mid) ? ans = mid, r = mid - 1 : l = mid + 1;
}printf("%d\n", ans);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template<typename T>
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
Ex - 01? Queries
题面
给定长度为 $ N $ 的仅包含 0,1,? 的字符串 $ S $,给定 $ Q $ 组询问 $ (x_1, c_1), (x_2, c_2), \cdots, (x_q, c_q) $,每次将原字符串中 $ x_i $ 位置的字符改为 $ c_i $,然后输出 $ S $ 有多少种非空子串,? 需任意替换为 0 或 1。
Solution
太长了这里就直接放个链接吧。。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define MAXN (int)(1e5 + 100)
#define MOD (int)(998244353)
template< typename T = int >
inline T read(void);
int N, Q;
int S[MAXN];
struct Matrix3{
int val[3][3];
Matrix3(int v00, int v01, int v02, int v10, int v11, int v12, int v20, int v21, int v22):
val{
{v00, v01, v02},
{v10, v11, v12},
{v20, v21, v22}
}{;}
Matrix3(int S):
val{
{1, S != 0, 0},
{S != 1, 1, 0},
{S != 1, S != 0, 1}
}{;}
Matrix3(int val[][3]){for(int i = 0; i <= 2; ++i)for(int j = 0; j <= 2; ++j)this->val[i][j] = val[i][j];}
Matrix3(void) = default;
friend const Matrix3 operator * (const Matrix3 &x, const Matrix3 &y){
int val[3][3]; memset(val, 0, sizeof val);
for(int i = 0; i <= 2; ++i)for(int j = 0; j <= 2; ++j)for(int p = 0; p <= 2; ++p)
val[i][j] = ((ll)val[i][j] + (ll)x.val[i][p] * y.val[p][j] % MOD) % MOD;
return Matrix3(val);
}
void Print(void){
for(int i = 0; i <= 2; ++i)for(int j = 0; j <= 2; ++j)
printf("%d%c", val[i][j], j == 2 ? '\n' : ' ');
}
}mt[MAXN];
class SegTree{
private:
Matrix3 tr[MAXN << 2];
#define LS (p << 1)
#define RS (LS | 1)
#define MID ((gl + gr) >> 1)
public:
void Pushup(int p){tr[p] = tr[LS] * tr[RS];}
void Build(int p = 1, int gl = 1, int gr = N){
if(gl == gr)return tr[p] = mt[gl = gr], void();
Build(LS, gl, MID);
Build(RS, MID + 1, gr);
Pushup(p);
}
void Modify(int idx, Matrix3 v, int p = 1, int gl = 1, int gr = N){
if(gl == gr)return tr[p] = v, void();
if(idx <= MID)Modify(idx, v, LS, gl, MID);
else Modify(idx, v, RS, MID + 1, gr);
Pushup(p);
}
Matrix3 Query(void){return tr[1];}
}st;
int main(){
N = read(), Q = read();
string s; cin >> s;
for(int i = 1; i <= (int)s.size(); ++i)
S[i] = s.at(i - 1) == '?' ? -1 : int(s.at(i - 1) - '0'),
mt[i] = Matrix3(S[i]);
st.Build();
Matrix3 origin(0, 0, 1, 0, 0, 0, 0, 0, 0);
while(Q--){
int p = read();
char c = getchar(); while(c != '0' && c != '1' && c != '?')c = getchar();
int flag = c == '?' ? -1 : int(c - '0');
st.Modify(p, Matrix3(flag));
auto ans = origin * st.Query();
printf("%d\n", (int)((ll)(ans.val[0][0] + ans.val[0][1]) % MOD));
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
UPD
update-2022_10_24 初稿

浙公网安备 33010602011771号