AtCoder Beginner Contest 270 题解
AtCoder Beginner Contest 270 Solution
更好的阅读体验戳此进入
题面链接
题面 Luogu 链接
abc不说了(该说不说这一场前三题分类讨论是真麻
[ABC270D] Stones
题面
Takahashi 和 Aoki 在玩一个取石子的游戏。
刚开始,有
现在,他们要按照以下规则轮流取石子:
-
对于每次操作,他可以选择一个
( ),这时他会取走 块石子。 -
当一个人没法取石子时,游戏结束。
现在,Takahashi 先取石子,Aoki 后取石子。
他们都想尽可能的最大化他们自己取走的石子数量。
若他们都以最优策略取石子,最后 Takahashi 会取走多少块石子?
Solution
开始以为是无脑贪心(主要是 D 题我以为会是很水那种
然后发现贪心是假的,就类似背包不能无脑装最大一样。所以考虑 DP,最开始想到
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.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 void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
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, K;
int A[110];
int dp[11000][2];
// int ans(0); bool flag(true);
// basic_string < int > rem;
int main(){
N = read(), K = read();
for(int i = 1; i <= K; ++i)A[i] = read();
for(int i = 1; i <= N; ++i){
for(int j = K; j >= 1; --j){
if(i >= A[j])
dp[i][0] = max(dp[i][0], dp[i - A[j]][1] + A[j]),
dp[i][1] = i - dp[i][0];
// else
// dp[i][j][0] = dp[i][1], dp[i][1] = dp[i][0];
}
}//int ans(0);
// for(int i = 1; i <= K; ++i)ans = max(ans, dp[N][i][0]);
printf("%d\n", dp[N][0]);
// for(int i = 1; i <= K; ++i)rem += read();
// while(!rem.empty() && N){
// while(!rem.empty() && rem.back() > N)rem.pop_back();
// if(rem.empty())break;
// ans += rem.back() * flag, flag ^= true, N -= rem.back();
// }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);
int 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;
}
[ABC270E] Apple Baskets on Circle
题面
存在
Solution
题解区怎么都是二分答案的做法,来一发 VP 时糊出来的更加无脑的模拟做法。
首先假设一圈里有
然后注意其中有一步 __int128_t
。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.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 void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
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; ll K;
ll A[210000];
priority_queue < ll, vector < ll >, greater < ll > > buc;
int main(){
N = read(), K = read < ll >();
ll cur(0);
for(int i = 1; i <= N; ++i)if((A[i] = read < ll >()))buc.push(A[i]), ++cur;
ll minus(0);
while(!buc.empty()){
ll v = buc.top() - minus; buc.pop();
if((__int128_t)cur * v <= K)K -= cur * v, minus += v, --cur;
else{minus += K / cur, K -= K / cur * cur; break;}
}
for(int i = 1; i <= N; ++i)A[i] = max(0ll, A[i] - minus);
for(int i = 1; i <= N && K; ++i)if(A[i])--A[i], --K;
for(int i = 1; i <= N; ++i)printf("%lld%c", A[i], i == N ? '\n' : ' ');
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int 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;
}
[ABC270F] Transportation
题面
有
- 对于
,可以花 的贡 号点建一个机场 . - 对于
,可以花 的贡献在 号点建一个港口 . - 对于
,可以花 的贡献在 号点到 号点连一条无向边 .
如果两个点
都有机场 . 都有港口 . 到 有边 .
问至少花多少代价才能让所有点连通 .
Solution
考虑新建两个点,对
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.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 void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
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);
// struct Edge{
// Edge* nxt;
// int to;
// ll val;
// OPNEW;
// }ed[410000];
// ROPNEW;
// Edge* head[210000];
ll X[210000], Y[210000];
int N, M;
ll ans(LONG_LONG_MAX);
struct Edge{
int s, t; ll val;
friend const bool operator < (const Edge &a, const Edge &b){
return a.val < b.val;
}
};
basic_string < Edge > edgs, basic_edgs;
class UnionFind{
private:
int fa[210000];
public:
void Clear(void){for(int i = 1; i <= 201000; ++i)fa[i] = i;}
int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}
void Union(int s, int t){fa[Find(s)] = fa[Find(t)];}
}uf;
ll MST(void){
uf.Clear();
ll ret(0);
sort(edgs.begin(), edgs.end());
for(auto e : edgs)
if(uf.Find(e.s) != uf.Find(e.t))
uf.Union(e.s, e.t), ret += e.val;
for(int i = 1; i <= N - 1; ++i)if(uf.Find(i) != uf.Find(i + 1))return LONG_LONG_MAX;
return ret;
}
int main(){
N = read(), M = read();
for(int i = 1; i <= N; ++i)X[i] = read();
for(int i = 1; i <= N; ++i)Y[i] = read();
for(int i = 1; i <= M; ++i){
int s = read(), t = read(), v = read();
// head[s] = new Edge{head[s], t, v};
// head[t] = new Edge{head[t], s, v};
basic_edgs += Edge{s, t, v};
}edgs += basic_edgs;
ans = min(ans, MST());
// printf("%lld\n", ans);
for(int i = 1; i <= N; ++i)edgs += Edge{i, N + 1, X[i]};
++N;
ans = min(ans, MST());
// printf("%lld\n", ans);
edgs.clear();
edgs += basic_edgs;
for(int i = 1; i <= N - 1; ++i)edgs += Edge{i, N, Y[i]};
ans = min(ans, MST());
// printf("%lld\n", ans);
for(int i = 1; i <= N - 1; ++i)edgs += Edge{i, N + 1, X[i]};
++N;
ans = min(ans, MST());
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);
int 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;
}
[ABC270G] Sequence in mod P
题面
对于某个无穷序列
求最小的 -1
。
多组数据,记
保证
保证
Solution
大概就是递推转通向,然后发现可以直接 BSGS 解决。
然后就是有一大堆特判的细节需要考虑一下。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.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 void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
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 MOD, A, B, S, G;
unordered_map < ll, int > mp;
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;
}
ll inv(ll v){return qpow(v, MOD - 2);}
ll BSGS(ll A, ll B){
mp.clear();
int lim = ceil(sqrt(MOD));
ll base(1), mul(1);
for(ll i = 1; i <= lim; ++i)(base *= A) %= MOD, mp[B * base % MOD] = i;
for(ll i = 1; i <= lim; ++i){
(mul *= base) %= MOD;
if(mp.find(mul) != mp.end())return i * lim - mp[mul];
}return -1;
}
int main(){
// freopen("in.txt", "r", stdin);
int T = read();
while(T--){
MOD = read(), A = read(), B = read(), S = read(), G = read();
ll V = (G + B * inv(A - 1) % MOD) % MOD * inv((S + B * inv(A - 1) % MOD) % MOD) % MOD;
if(S == G)printf("0\n");
else if(!A)printf("%d\n", B == G ? 1 : -1);
else if(A == 1){
if(!B)printf("-1\n");
else printf("%lld\n", ((G - S) * inv(B) % MOD + MOD) % MOD);
}else printf("%lld\n", BSGS(A, V));
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int 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;
}
[ABC270Ex] add 1
题面
给定序列
Solution
大概是一道没有什么高端的算法,仅靠推式子的难度评黑的题。
首先我们不难想到,如果设当前计数器的值为
然后不太严谨地思考一下不难发现,我们每次是使除了选择的其它的计数器都加一,所以拖后腿的一定是
于是此时不难想到一个较为简单的状态:令
显然
转化一下:
现在不难发现即较小的都在左侧,较大的都在右侧,不过这个转移仍然不行,也就是我们是已知
考虑令
显然
类比一下之前的推出来:
显然:
不难发现对于固定的
对于
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.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 void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
using namespace std;
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 (998244353ll)
template < typename T = int >
inline T read(void);
struct Matrix2{
ll v00, v01, v10, v11;
friend Matrix2 operator * (const Matrix2 &a, const Matrix2 &b){
return Matrix2{
(a.v00 * b.v00 % MOD + a.v01 * b.v10 % MOD) % MOD,
(a.v00 * b.v01 % MOD + a.v01 * b.v11 % MOD) % MOD,
(a.v10 * b.v00 % MOD + a.v11 * b.v10 % MOD) % MOD,
(a.v10 * b.v01 % MOD + a.v11 * b.v11 % MOD) % MOD
};
}
};
Matrix2 base{1, 0, 0, 1};
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;
}
ll inv(ll v){return qpow(v, MOD - 2);}
Matrix2 qpow(Matrix2 a, ll b){
Matrix2 ret(base), mul(a);
while(b){
if(b & 1)ret = ret * mul;
b >>= 1;
mul = mul * mul;
}return ret;
}
int N;
ll A[210000];
int main(){
N = read();
for(int i = 1; i <= N; ++i)A[i] = read < ll >();
Matrix2 ans{0, 1, 0, 0};
ll cur(0);
for(int i = N - 1; i >= 1; --i){
ll B = N * inv(i) % MOD, C = (N - cur) * inv(i) % MOD;
ans = ans * qpow(Matrix2{B, 0, C, 1}, A[i + 1] - A[i]);
(cur += ans.v00) %= MOD;
}printf("%lld\n", (ans.v00 % MOD + MOD) % MOD);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int 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-2023_01_27 初稿
本文作者:tsawke
本文链接:https://www.cnblogs.com/tsawke/p/17124373.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步