[zoj3593]扩展欧几里得+三分

题意:给一个数A,有6种操作,+a,-a,+b,-b,+(a+b),-(a+b),每次选择一种,用最少的次数变成B。

思路:由于不同的操作先后顺序对最后的结果没有影响,并且加一个数与减一个相同的数不能同时有,如果有,把它们都去掉结果更优。所以不妨设+a操作进行了x次(x为负表示-a操作进行了|x|次,y同理),+b操作进行了y次,那么问题转化为ax + by = |A-B|的解,使得结果最小,其中如果x,y异号,结果为|x|+|y|,同号则为max(|x|,|y|,因为+a,+b或-a,-b可以合并)。令c=|A-B|,如果c%gcd(a,b)!=0,这个显然是没有解的,直接输出-1。否则令a=a/g,b=b/g,c=c/g,其中gcd(a,b)=1,令ax+by=1的一个解为(x0,y0),则方程的通解可以表示为(x0+kb,y0-ka),下面进行关键的一步:由于ax+bx=c可以转化为c个ax+bx=1相加,所以ax+bx=c的解可以表示为(cx0+Kb,cy0-Ka)(K取任意整数),这里a,b,c,x0,y0都是已知的,K是个变量,K确定后那么答案也就确定了,由于答案是K的单峰函数所以可以三分一下,求得最小答案。由于K的范围不确定,需要用大整数=_=(醉了)!具体看代码。

  1 #pragma comment(linker, "/STACK:10240000,10240000")

  2 

  3 #include <iostream>

  4 #include <cstdio>

  5 #include <algorithm>

  6 #include <cstdlib>

  7 #include <cstring>

  8 #include <map>

  9 #include <queue>

 10 #include <deque>

 11 #include <cmath>

 12 #include <vector>

 13 #include <ctime>

 14 #include <cctype>

 15 #include <set>

 16 #include <bitset>

 17 #include <functional>

 18 #include <numeric>

 19 #include <stdexcept>

 20 #include <utility>

 21 

 22 using namespace std;

 23 

 24 #define mem0(a) memset(a, 0, sizeof(a))

 25 #define mem_1(a) memset(a, -1, sizeof(a))

 26 #define lson l, m, rt << 1

 27 #define rson m + 1, r, rt << 1 | 1

 28 #define define_m int m = (l + r) >> 1

 29 #define rep_up0(a, b) for (int a = 0; a < (b); a++)

 30 #define rep_up1(a, b) for (int a = 1; a <= (b); a++)

 31 #define rep_down0(a, b) for (int a = b - 1; a >= 0; a--)

 32 #define rep_down1(a, b) for (int a = b; a > 0; a--)

 33 #define all(a) (a).begin(), (a).end()

 34 #define lowbit(x) ((x) & (-(x)))

 35 #define constructInt4(name, a, b, c, d) name(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), d(d) {}

 36 #define constructInt3(name, a, b, c) name(int a = 0, int b = 0, int c = 0): a(a), b(b), c(c) {}

 37 #define constructInt2(name, a, b) name(int a = 0, int b = 0): a(a), b(b) {}

 38 #define pchr(a) putchar(a)

 39 #define pstr(a) printf("%s", a)

 40 #define sstr(a) scanf("%s", a)

 41 #define sint(a) scanf("%d", &a)

 42 #define sint2(a, b) scanf("%d%d", &a, &b)

 43 #define sint3(a, b, c) scanf("%d%d%d", &a, &b, &c)

 44 #define pint(a) printf("%d\n", a)

 45 #define test_print1(a) cout << "var1 = " << a << endl

 46 #define test_print2(a, b) cout << "var1 = " << a << ", var2 = " << b << endl

 47 #define test_print3(a, b, c) cout << "var1 = " << a << ", var2 = " << b << ", var3 = " << c << endl

 48 

 49 typedef long long LL;

 50 typedef pair<int, int> pii;

 51 typedef vector<int> vi;

 52 

 53 const int dx[8] = {0, 0, -1, 1, 1, 1, -1, -1};

 54 const int dy[8] = {-1, 1, 0, 0, 1, -1, 1, -1 };

 55 const int maxn = 102;

 56 const int md = 10007;

 57 const int inf = 1e9 + 7;

 58 const LL inf_L = 1e18 + 7;

 59 const double pi = acos(-1.0);

 60 const double eps = 1e-4;

 61 

 62 template<class T>T gcd(T a, T b){return b==0?a:gcd(b,a%b);}

 63 template<class T>bool max_update(T &a,const T &b){if(b>a){a = b; return true;}return false;}

 64 template<class T>bool min_update(T &a,const T &b){if(b<a){a = b; return true;}return false;}

 65 template<class T>T condition(bool f, T a, T b){return f?a:b;}

 66 template<class T>void copy_arr(T a[], T b[], int n){rep_up0(i,n)a[i]=b[i];}

 67 int make_id(int x, int y, int n) { return x * n + y; }

 68 

 69 const int maxI = 1e8;

 70 const int Len = 8;

 71 

 72 struct BigInt {

 73     vi num;

 74     bool symbol;

 75     BigInt() { num.clear(); symbol = 0; }

 76     BigInt(int x) { symbol = 0; if (x < 0) { symbol = 1; x = -x; } num.push_back(x % maxI); if (x >= maxI) num.push_back(x / maxI); }

 77     BigInt(bool s, vi x) { symbol = s;  num = x; }

 78     BigInt(char s[]) {

 79         int len = strlen(s), x = 1, sum = 0, p = s[0] == '-';

 80         symbol = p;

 81         for (int i = len - 1; i >= p; i--) {

 82             sum += (s[i] - '0') * x;

 83             x *= 10;

 84             if (x == 1e8 || i == p) {

 85                 num.push_back(sum);

 86                 sum = 0;

 87                 x = 1;

 88             }

 89         }

 90         while (num.back() == 0 && num.size() > 1) num.pop_back();

 91     }

 92 

 93     void push(int x) { num.push_back(x); }

 94 

 95     BigInt abs() const { return BigInt(false, num); }

 96 

 97     bool smaller(const vi &a, const vi &b) const {

 98         if (a.size() != b.size()) return a.size() < b.size();

 99         for (int i = a.size() - 1; i >= 0; i--) {

100             if (a[i] != b[i]) return a[i] < b[i];

101         }

102         return 0;

103     }

104 

105     bool operator < (const BigInt &p) const {

106         if (symbol && !p.symbol) return true;

107         if (!symbol && p.symbol) return false;

108         if (symbol && p.symbol) return smaller(p.num, num);

109         return smaller(num, p.num);

110     }

111 

112     bool operator > (const BigInt &p) const {

113         return p < *this;

114     }

115 

116     bool operator == (const BigInt &p) const {

117         return !(p < *this) && !(*this < p);

118     }

119 

120     bool operator >= (const BigInt &p) const {

121         return !(*this < p);

122     }

123 

124     bool operator <= (const BigInt &p) const {

125         return !(p < *this);

126     }

127 

128     vi add(const vi &a, const vi &b) const {

129         vi c;

130         c.clear();

131         int x = 0;

132         for (int i = 0; i < a.size(); i++) {

133             x += a[i];

134             if (i < b.size()) x += b[i];

135             c.push_back(x % maxI);

136             x /= maxI;

137         }

138         for (int i = a.size(); i < b.size(); i++) {

139             x += b[i];

140             c.push_back(x % maxI);

141             x /= maxI;

142         }

143         if (x) c.push_back(x);

144         while (c.back() == 0 && c.size() > 1) c.pop_back();

145         return c;

146     }

147 

148     vi sub(const vi &a, const vi &b) const {

149         vi c;

150         c.clear();

151         int x = 1;

152         for (int i = 0; i < b.size(); i++) {

153             x += maxI + a[i] - b[i] - 1;

154             c.push_back(x % maxI);

155             x /= maxI;

156         }

157         for (int i = b.size(); i < a.size(); i++) {

158             x += maxI + a[i] - 1;

159             c.push_back(x % maxI);

160             x /= maxI;

161         }

162         while (c.back() == 0 && c.size() > 1) c.pop_back();

163         return c;

164     }

165 

166     vi mul(const vi &a, const vi &b) const {

167         vi c;

168         c.resize(a.size() + b.size());

169         for (int i = 0; i < a.size(); i++) {

170             for (int j = 0; j < b.size(); j++) {

171                 LL tmp = (LL)a[i] * b[j] + c[i + j];

172                 c[i + j + 1] += tmp / maxI;

173                 c[i + j] = tmp % maxI;

174             }

175         }

176         while (c.back() == 0 && c.size() > 1) c.pop_back();

177         return c;

178     }

179 

180     vi div(const vi &a, const vi &b) const {

181         vi c(a.size()), x(1, 0), y(1, 0), z(1, 0), t(1, 0);

182         y.push_back(1);

183         for (int i = a.size() - 1; i >= 0; i--) {

184             z[0] = a[i];

185             x = add(mul(x, y), z);

186             if (smaller(x, b)) continue;

187             int l = 1, r = maxI - 1;

188             while (l < r) {

189                 int m = (l + r + 1) >> 1;

190                 t[0] = m;

191                 if (smaller(x, mul(b, t))) r = m - 1;

192                 else l = m;

193             }

194             c[i] = l;

195             t[0] = l;

196             x = sub(x, mul(b, t));

197         }

198         while (c.back() == 0 && c.size() > 1) c.pop_back();

199         return c;

200     }

201 

202     BigInt operator + (const BigInt &p) const{

203         if (!symbol && !p.symbol) return BigInt(false, add(num, p.num));

204         if (!symbol && p.symbol) return *this >= p.abs()? BigInt(false, sub(num, p.num)) : BigInt(true, sub(p.num, num));

205         if (symbol && !p.symbol) return (*this).abs() > p? BigInt(true, sub(num, p.num)) : BigInt(false, sub(p.num, num));

206         return BigInt(true, add(num, p.num));

207     }

208 

209     BigInt operator - (const BigInt &p) const {

210         return *this + BigInt(!p.symbol, p.num);

211     }

212 

213     BigInt operator * (const BigInt &p) const {

214         BigInt res(symbol ^ p.symbol, mul(num, p.num));

215         if (res.symbol && res.num.size() == 1 && res.num[0] == 0) res.symbol = false;

216         return res;

217     }

218 

219     BigInt operator / (const BigInt &p) const {

220         if (p == BigInt(0)) return p;

221         BigInt res(symbol ^ p.symbol, div(num, p.num));

222         if (res.symbol && res.num.size() == 1 && res.num[0] == 0) res.symbol = false;

223         return res;

224     }

225 

226     BigInt operator % (const BigInt &p) const {

227         return *this - *this / p * p;

228     }

229 

230     void show() const {

231         if (symbol) putchar('-');

232         printf("%d", num[num.size() - 1]);

233         for (int i = num.size() - 2; i >= 0; i--) {

234             printf("%08d", num[i]);

235         }

236         putchar('\n');

237     }

238 

239     int TotalDigit() const {

240         int x = num[num.size() - 1] / 10, t = 1;

241         while (x) {

242             x /= 10;

243             t++;

244         }

245         return t + (num.size() - 1) * Len;

246     }

247 

248 };

249 typedef BigInt bi;

250 bi A, B, a, b;

251 bi x, y, d, t;

252 char s[100];

253 void gcd(bi a, bi b, bi &d, bi &x, bi &y) {

254     if (b == 0) {

255         d = a;

256         x = 1;

257         y = 0;

258     }

259     else {

260         gcd(b, a % b, d, y, x);

261         y = y - x * (a / b);

262     }

263 }

264 

265 bi f(bi k) {

266     bi p = t * x + k * b;

267     bi q = t * y - k * a;

268     if (p > 0 && q > 0 || p < 0 && q < 0) return max(p.abs(), q.abs());

269     return p.abs() + q.abs();

270 }

271 

272 int main() {

273     //freopen("in.txt", "r", stdin);

274     int T;

275     cin >> T;

276     while (T --) {

277         cin >> s;

278         A = bi(s);

279         cin >> s;

280         B = bi(s);

281         cin >> s;

282         a = bi(s);

283         cin >> s;

284         b = bi(s);

285         t = (A - B).abs();

286         bi g = gcd(a, b);

287         if (!(t % g == 0)) {

288             puts("-1");

289             continue;

290         }

291         a = a / g;

292         b = b / g;

293         t = t / g;

294 

295         gcd(a, b, d, x, y);

296 

297         bi l = "-100000000000000000", r = "100000000000000000";

298         while (r - l > 2) {

299             bi m1 = l + (r - l) / 3, m2 = r - (r - l) / 3;

300             if (f(m1) > f(m2)) l = m1 + 1;

301             else r = m2;

302         }

303         bi ans = f(l);

304         min_update(ans, f(l + 1));

305         min_update(ans, f(l + 2));

306         ans.show();

307     }

308 }
View Code

 

你可能感兴趣的:(ZOJ)