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