存在
果然难题的尽头是推式子。
首先令买的
然后考虑将中间的
然后将前面的分式带进去并进一步化简:
发现
发现式子中出现了大量的
然后发现第二项可以转化为:
然后考虑一三项,同样尽量用
此时若我们令:
则原式转化为:
写的更明显一点,我们就是要求:
显然购买方案一共有
显然我们是需要尽量使
然后这里我们显然不能枚举实数,于是考虑什么时候骰子之间的大小关系会发生变化,考虑存在以下情况,当
显然对于这两种情况的转折点存在于:
并且此时仅有
所以我们
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 初稿