AtCoder Beginner Contest 257 Solution更好的阅读体验戳此进入题面链接题面 Luogu 链接abc 跳了[ABC257D] Jumping Takahashi 2题面SolutionCode[ABC257E] Addition and Multiplication 2题面SolutionCode[ABC257F] Teleporter Setting题面SolutionCode[ABC257G] Prefix Concatenation题面SolutionCode[ABC257Ex] Dice Sum 2题面SolutionCodeUPD
给定
不难发现问题可以转化为,我们要选择一个点,求使得这个点能够到达其它所有点的最大代价,然后求所有起点最大代价的最小值,这东西有点像全源最短路,且数据范围很小。于是不难想到一步转化,可以将原不等式转化为
xxxxxxxxxx
661
2
3
4
5
6
7
8
9
10
11using namespace std;
12
13mt19937 rnd(random_device{}());
14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
15bool rnddd(int x){return rndd(1, 100) <= x;}
16
17typedef unsigned int uint;
18typedef unsigned long long unll;
19typedef long long ll;
20typedef long double ld;
21
22template < typename T = int >
23inline T read(void);
24
25int N;
26struct Node{ll x, y, p;}nod[300];
27ll dis[300][300];
28ll ans(LONG_LONG_MAX);
29
30int main(){
31 N = read();
32 for(int i = 1; i <= N; ++i)nod[i].x = read(), nod[i].y = read(), nod[i].p = read();
33 for(int i = 1; i <= N; ++i)
34 for(int j = 1; j <= N; ++j)
35 if(i == j)dis[i][j] = 0;
36 else
37 dis[i][j] = (ll)ceil((ld)(abs(nod[i].x - nod[j].x) + abs(nod[i].y - nod[j].y)) / (ld)nod[i].p),
38 dis[j][i] = (ll)ceil((ld)(abs(nod[i].x - nod[j].x) + abs(nod[i].y - nod[j].y)) / (ld)nod[j].p);
39 for(int k = 1; k <= N; ++k)
40 for(int i = 1; i <= N; ++i)
41 for(int j = 1; j <= N; ++j)
42 dis[i][j] = min(dis[i][j], max(dis[i][k], dis[k][j]));
43 for(int s = 1; s <= N; ++s){
44 ll mx(-1);
45 for(int t = 1; t <= N; ++t)mx = max(mx, dis[s][t]);
46 ans = min(ans, mx);
47 }printf("%lld\n", ans);
48 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
49 return 0;
50}
51
52template < typename T >
53inline T read(void){
54 T ret(0);
55 int flag(1);
56 char c = getchar();
57 while(c != '-' && !isdigit(c))c = getchar();
58 if(c == '-')flag = -1, c = getchar();
59 while(isdigit(c)){
60 ret *= 10;
61 ret += int(c - '0');
62 c = getchar();
63 }
64 ret *= flag;
65 return ret;
66}
高桥君有一个整数
高桥君可以无限执行以下操作:
高桥君有
在保证长度最长的前提下尽量在更高位选择更大的数即可。
xxxxxxxxxx
621
2
3
4
5
6
7
8
9
10
11using namespace std;
12
13mt19937 rnd(random_device{}());
14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
15bool rnddd(int x){return rndd(1, 100) <= x;}
16
17typedef unsigned int uint;
18typedef unsigned long long unll;
19typedef long long ll;
20typedef long double ld;
21
22template < typename T = int >
23inline T read(void);
24
25int N;
26int C[20];
27int mn(INT_MAX), mnp(-1);
28basic_string < int > ans;
29
30int main(){
31 N = read();
32 for(int i = 1; i <= 9; ++i){
33 C[i] = read();
34 if(C[i] < mn)mn = C[i], mnp = i;
35 }
36 ll mxLen = N / mn;
37 for(int i = 1; i <= mxLen; ++i)
38 for(int j = 9; j >= mnp; --j)
39 if(N - C[j] >= (mxLen - i) * mn){
40 N -= C[j], ans += j; break;
41 }
42 for(auto d : ans)printf("%d", d);
43 printf("\n");
44 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
45 return 0;
46}
47
48template < typename T >
49inline T read(void){
50 T ret(0);
51 int flag(1);
52 char c = getchar();
53 while(c != '-' && !isdigit(c))c = getchar();
54 if(c == '-')flag = -1, c = getchar();
55 while(isdigit(c)){
56 ret *= 10;
57 ret += int(c - '0');
58 c = getchar();
59 }
60 ret *= flag;
61 return ret;
62}
存在
算是一道挺好的题。首先我们可以进行如下转化,对于所有
xxxxxxxxxx
881
2
3
4
5
6
7
8
9
10
11using namespace std;
12
13mt19937 rnd(random_device{}());
14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
15bool rnddd(int x){return rndd(1, 100) <= x;}
16
17typedef unsigned int uint;
18typedef unsigned long long unll;
19typedef long long ll;
20typedef long double ld;
21
22template < typename T = int >
23inline T read(void);
24
25struct Edge{
26 Edge* nxt;
27 int to;
28 OPNEW;
29}ed[610000];
30ROPNEW(ed);
31Edge* head[310000];
32
33int N, M;
34int dis1[310000], disn[310000];
35
36void bfs1(void){
37 memset(dis1, 0x3f, sizeof dis1);
38 bitset < 310000 > vis; vis.reset();
39 queue < int > cur; cur.push(1), vis[1] = true, dis1[1] = 0;
40 while(!cur.empty()){
41 int p = cur.front(); cur.pop();
42 for(auto i = head[p]; i; i = i->nxt)
43 if(!vis[SON])
44 vis[SON] = true, dis1[SON] = dis1[p] + 1, cur.push(SON);
45 }
46}
47void bfsn(void){
48 memset(disn, 0x3f, sizeof disn);
49 bitset < 310000 > vis; vis.reset();
50 queue < int > cur; cur.push(N), vis[N] = true, disn[N] = 0;
51 while(!cur.empty()){
52 int p = cur.front(); cur.pop();
53 for(auto i = head[p]; i; i = i->nxt)
54 if(!vis[SON])
55 vis[SON] = true, disn[SON] = disn[p] + 1, cur.push(SON);
56 }
57}
58
59int main(){
60 N = read(), M = read();
61 for(int i = 1; i <= M; ++i){
62 int s = read(), t = read();
63 head[s] = new Edge{head[s], t};
64 head[t] = new Edge{head[t], s};
65 }bfs1(), bfsn();
66 for(int i = 1; i <= N; ++i){
67 int ans = min({dis1[N], dis1[0] + disn[i], dis1[i] + disn[0]});
68 printf("%d%c", ans >= 0x3f3f3f3f ? -1 : ans, i == N ? '\n' : ' ');
69 }
70 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
71 return 0;
72}
73
74template < typename T >
75inline T read(void){
76 T ret(0);
77 int flag(1);
78 char c = getchar();
79 while(c != '-' && !isdigit(c))c = getchar();
80 if(c == '-')flag = -1, c = getchar();
81 while(isdigit(c)){
82 ret *= 10;
83 ret += int(c - '0');
84 c = getchar();
85 }
86 ret *= flag;
87 return ret;
88}
给定仅存在小写英文字母的字符串 -1
。
首先
不难发现这个
首先有一个思路,已知
然后根据这个思路我们每次转移只需要找到最小的合法 next
数组维护。
具体地,不难发现我们这个东西求的可以转化为求 border,具体地,我们将 P = S + '#' + T
,这样我们对 #
。
最终 DP 优化为
同时还有一种方法,发现修改状态为后缀可以支持逆序转移,于是转移变为:
此时发现每次可以转移的
xxxxxxxxxx
611
2
3
4
5
6
7
8
9
10
11using namespace std;
12
13mt19937 rnd(random_device{}());
14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
15bool rnddd(int x){return rndd(1, 100) <= x;}
16
17typedef unsigned int uint;
18typedef unsigned long long unll;
19typedef long long ll;
20typedef long double ld;
21
22template < typename T = int >
23inline T read(void);
24
25string S, T;
26char s[1100000];
27int dp[1100000];
28int nxt[1100000];
29
30int main(){
31 memset(dp, 0x3f, sizeof dp);
32 cin >> S >> T;
33 sprintf(s + 1, "%s#%s", S.c_str(), T.c_str());
34 int lenS = S.length(), lenT = T.length();
35 dp[lenS + 1] = 0;
36 int cur(0);
37 for(int i = 2; i <= lenS + lenT + 1; ++i){
38 while(cur && s[cur + 1] != s[i])cur = nxt[cur];
39 if(s[cur + 1] == s[i])++cur;
40 if(i > lenS + 1)dp[i] = dp[i - cur] + 1;
41 nxt[i] = cur;
42 }printf("%d\n", dp[lenS + lenT + 1] < 0x3f3f3f3f ? dp[lenS + lenT + 1] : -1);
43 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
44 return 0;
45}
46
47template < typename T >
48inline T read(void){
49 T ret(0);
50 int flag(1);
51 char c = getchar();
52 while(c != '-' && !isdigit(c))c = getchar();
53 if(c == '-')flag = -1, c = getchar();
54 while(isdigit(c)){
55 ret *= 10;
56 ret += int(c - '0');
57 c = getchar();
58 }
59 ret *= flag;
60 return ret;
61}
存在
果然难题的尽头是推式子。
首先令买的
然后考虑将中间的
然后将前面的分式带进去并进一步化简:
发现
发现式子中出现了大量的
然后发现第二项可以转化为:
然后考虑一三项,同样尽量用
此时若我们令:
则原式转化为:
写的更明显一点,我们就是要求:
显然购买方案一共有
显然我们是需要尽量使
然后这里我们显然不能枚举实数,于是考虑什么时候骰子之间的大小关系会发生变化,考虑存在以下情况,当
显然对于这两种情况的转折点存在于:
并且此时仅有
所以我们
Tips:实现时为了便于排序,且 long long
的范围,我们可以考虑按照
Tips:还有一个我调了很久的细节,就是过程中不能取模,否则大小关系会变化,导致答案错误。
然后按照这个思路实现之后大概是这样:
xxxxxxxxxx
941
2
3
4
5
6
7
8
9
10
11using namespace std;
12
13mt19937 rnd(random_device{}());
14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
15bool rnddd(int x){return rndd(1, 100) <= x;}
16
17typedef unsigned int uint;
18typedef unsigned long long unll;
19typedef long long ll;
20typedef long double ld;
21
22
23
24template < typename T = int >
25inline T read(void);
26
27ll inv36;
28int N, K;
29ll C[1100];
30ll A[1100][10];
31ll X[1100], Y[1100];
32struct MyPair{int first, second;};
33map < ld, basic_string < MyPair > > mp;
34bitset < 1100 > inAns;
35ll ansX(0), ansY(0);
36ll ans(LONG_LONG_MIN);
37int idx[1100];
38
39ll qpow(ll a, ll b){
40 ll ret(1), mul(a);
41 while(b){
42 if(b & 1)ret = ret * mul % MOD;
43 b >>= 1;
44 mul = mul * mul % MOD;
45 }return ret;
46}
47
48int main(){
49 inv36 = qpow(36ll, MOD - 2);
50 N = read(), K = read();
51 for(int i = 1; i <= N; ++i)C[i] = read(), idx[i] = i;
52 for(int i = 1; i <= N; ++i){
53 for(int j = 1; j <= 6; ++j)
54 A[i][j] = read(),
55 X[i] += A[i][j], //6Xi
56 Y[i] += 6 * A[i][j] * A[i][j]; //36Yi
57 Y[i] -= X[i] * X[i] + 36 * C[i];
58 }
59 for(int i = 1; i <= N; ++i)for(int j = i + 1; j <= N; ++j)
60 mp[(ld)(Y[j] - Y[i]) / (ld)(X[i] - X[j])] += MyPair{i, j};
61 ld k = mp.begin()->first - 0.1;
62 sort(idx + 1, idx + N + 1, [=](const int &a, const int &b)->bool{return k * (ld)X[a] + (ld)Y[a] > k * (ld)X[b] + (ld)Y[b];});
63 for(int i = 1; i <= K; ++i)
64 ansX += X[idx[i]], ansY += Y[idx[i]], inAns[idx[i]] = true;
65 ans = max(ans, ansX * ansX + ansY);
66 for(auto mdf : mp){
67 for(auto Pair : mdf.second){
68 int l = Pair.first, r = Pair.second;
69 if(inAns[l] ^ inAns[r]){
70 if(!inAns[l] && inAns[r])swap(l, r);
71 inAns[l] = false, inAns[r] = true;
72 ansX += -X[l] + X[r], ansY += -Y[l] + Y[r];
73 }
74 }ans = max(ans, ansX * ansX + ansY);
75 }printf("%lld\n", (ans % MOD * inv36 % MOD + MOD) % MOD);
76 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
77 return 0;
78}
79
80template < typename T >
81inline T read(void){
82 T ret(0);
83 int flag(1);
84 char c = getchar();
85 while(c != '-' && !isdigit(c))c = getchar();
86 if(c == '-')flag = -1, c = getchar();
87 while(isdigit(c)){
88 ret *= 10;
89 ret += int(c - '0');
90 c = getchar();
91 }
92 ret *= flag;
93 return ret;
94}
看起来没什么问题,但是交上去就会发现错了很多点,感觉可能是精度之类的问题,于是我们考虑去掉所有浮点数相关运算。
首先对于初始的排序,不难想到若将
然后对于修改之间的排序把式子推一下换成乘法即可。还有个细节就是我们在修改的时候应仅保留一些满足
xxxxxxxxxx
961
2
3
4
5
6
7
8
9
10
11using namespace std;
12
13mt19937 rnd(random_device{}());
14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
15bool rnddd(int x){return rndd(1, 100) <= x;}
16
17typedef unsigned int uint;
18typedef unsigned long long unll;
19typedef long long ll;
20typedef long double ld;
21
22
23
24template < typename T = int >
25inline T read(void);
26
27ll inv36;
28int N, K;
29ll C[1100];
30ll A[1100][10];
31ll X[1100], Y[1100];
32struct Node{
33 int l, r;
34 friend const bool operator < (const Node &a, const Node &b){
35 return (Y[a.r] - Y[a.l]) * (X[b.l] - X[b.r]) < (Y[b.r] - Y[b.l]) * (X[a.l] - X[a.r]);
36 }
37};
38basic_string < Node > mdfs;
39multimap < ld, pair < int, int > > mp;
40bitset < 1100 > inAns;
41ll ansX(0), ansY(0);
42ll ans(LONG_LONG_MIN);
43int idx[1100];
44
45ll qpow(ll a, ll b){
46 ll ret(1), mul(a);
47 while(b){
48 if(b & 1)ret = ret * mul % MOD;
49 b >>= 1;
50 mul = mul * mul % MOD;
51 }return ret;
52}
53
54int main(){
55 // freopen("in.txt", "r", stdin);
56 inv36 = qpow(36ll, MOD - 2);
57 N = read(), K = read();
58 for(int i = 1; i <= N; ++i)C[i] = read(), idx[i] = i;
59 for(int i = 1; i <= N; ++i){
60 for(int j = 1; j <= 6; ++j)
61 A[i][j] = read(),
62 X[i] += A[i][j], //6Xi
63 Y[i] += 6 * A[i][j] * A[i][j]; //36Yi
64 Y[i] -= X[i] * X[i] + 36 * C[i];
65 }
66 for(int i = 1; i <= N; ++i)for(int j = 1; j <= N; ++j)if(X[i] < X[j])mdfs += Node{i, j};
67 sort(mdfs.begin(), mdfs.end());
68 sort(idx + 1, idx + N + 1, [](const int &a, const int &b)->bool{return X[a] < X[b];});
69 for(int i = 1; i <= K; ++i)
70 ansX += X[idx[i]], ansY += Y[idx[i]], inAns[idx[i]] = true;
71 ans = max(ans, ansX * ansX + ansY);
72 for(auto mdf : mdfs)
73 if(inAns[mdf.l] && !inAns[mdf.r])
74 inAns[mdf.l] = false, inAns[mdf.r] = true,
75 ansX += -X[mdf.l] + X[mdf.r], ansY += -Y[mdf.l] + Y[mdf.r],
76 ans = max(ans, ansX * ansX + ansY);
77 printf("%lld\n", (ans % MOD * inv36 % MOD + MOD) % MOD);
78 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
79 return 0;
80}
81
82template < typename T >
83inline T read(void){
84 T ret(0);
85 int flag(1);
86 char c = getchar();
87 while(c != '-' && !isdigit(c))c = getchar();
88 if(c == '-')flag = -1, c = getchar();
89 while(isdigit(c)){
90 ret *= 10;
91 ret += int(c - '0');
92 c = getchar();
93 }
94 ret *= flag;
95 return ret;
96}
update-2022_12_19 初稿