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
给定
不难发现问题可以转化为,我们要选择一个点,求使得这个点能够到达其它所有点的最大代价,然后求所有起点最大代价的最小值,这东西有点像全源最短路,且数据范围很小。于是不难想到一步转化,可以将原不等式转化为
xxxxxxxxxx66123
45678910
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 else37 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}高桥君有一个整数
高桥君可以无限执行以下操作:
高桥君有
在保证长度最长的前提下尽量在更高位选择更大的数即可。
xxxxxxxxxx62123
45678910
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}存在
算是一道挺好的题。首先我们可以进行如下转化,对于所有
xxxxxxxxxx88123
45678910
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 优化为
同时还有一种方法,发现修改状态为后缀可以支持逆序转移,于是转移变为:
此时发现每次可以转移的
xxxxxxxxxx61123
45678910
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:还有一个我调了很久的细节,就是过程中不能取模,否则大小关系会变化,导致答案错误。
然后按照这个思路实现之后大概是这样:
xxxxxxxxxx94123
45678910
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
2223
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], //6Xi56 Y[i] += 6 * A[i][j] * A[i][j]; //36Yi57 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}看起来没什么问题,但是交上去就会发现错了很多点,感觉可能是精度之类的问题,于是我们考虑去掉所有浮点数相关运算。
首先对于初始的排序,不难想到若将
然后对于修改之间的排序把式子推一下换成乘法即可。还有个细节就是我们在修改的时候应仅保留一些满足
xxxxxxxxxx96123
45678910
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
2223
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], //6Xi63 Y[i] += 6 * A[i][j] * A[i][j]; //36Yi64 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 初稿