给定终点 -1
。
首先这道题应该很明显是分类讨论,但是找到的性质的多少也就决定了式子最终的复杂程度。
首先这八个向量分别对应了右、右上、上、
首先我们想到,若终点可以被一个向量表示,那么一定可以只用这个向量表示(废话)。
其次一个显而易见的性质,显然两个相邻的四向向量可以表示出其夹着的八向向量(但贡献会多
所以不难想到,如果一个向量可以被任意两个向量表示,那么就变成了一个简单的解方程的问题,而若解出来的解全都不合法(有负数或者不为整数),就说明这个向量无法被仅用两个向量表示。
而这里我们可以思考一下,对于某个象限内的终点,若我们可以用其对应的两个四向向量,那么是一定可以表示出来的,所以无法表示就说明我们一定不是有对应的两个四向向量的情况。
而如果是选择的一个四向向量和一个八向向量,那么我们再选一个四向向量上去是没意义的,因为都可以更优地被之前的一个四向向量和一个八向向量表示,所以我们可以考虑一下再选一个八向向量的情况,这个时候我们发现,若这个四向向量用了达到两次,那么就可以在不增加贡献的情况下用另外两个八向向量表示,所以对于这个情况我们可以转化为使用一个四向向量后再用另外两个八向向量解方程。
而对于初始选择两个八向向量在选择一个四向向量的情况与上一种情况本质相同。
同时我们继续思考就会发现再没有更多情况了。
于是我们现在梳理一下共有哪些可能:
令种类数
Tips:上文很多部分的再选一个等语言可能已经默认了额外选择的是相邻的或夹着的,因为其它部分情况的错误性过于显然,故不赘述了。
xxxxxxxxxx
991
2
3
4
5
6
7
8
9
10
11
12using namespace std;
13
14mt19937 rnd(random_device{}());
15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
16bool rnddd(int x){return rndd(1, 100) <= x;}
17
18typedef unsigned int uint;
19typedef unsigned long long unll;
20typedef long long ll;
21typedef long double ld;
22
23
24
25
26template < typename T = int >
27inline T read(void);
28
29ll A, B;
30ll ans(INFLL);
31ll dx[10] = {0, 1, 1, 0, -1, -1, -1, 0, 1};
32ll dy[10] = {0, 0, 1, 1, 1, 0, -1, -1, -1};
33bitset < 10 > exists;
34
35bool isInteger(ld v){
36 return fabs(ld(ll(v)) - v) < EPS;
37}
38void Check(int i, int j, int base = 0){
39 if(dx[i] * dy[j] - dx[j] * dy[i] == 0)return;
40 ld v1 = (ld)(B * dx[i] - A * dy[i]) / (dx[i] * dy[j] - dx[j] * dy[i]);
41 if(v1 <= -EPS || !isInteger(v1))return;
42 ld v2 = (ld)(B * dx[j] - A * dy[j]) / (dx[j] * dy[i] - dx[i] * dy[j]);
43 if(v2 <= -EPS || !isInteger(v2))return;
44 ans = min(ans, ll(v1) + ll(v2) + base);
45}
46
47int main(){
48 // freopen("in.txt", "r", stdin);
49 // freopen("out.txt", "w", stdout);
50 int T = read();
51 while(T--){
52 A = read(), B = read();
53 for(int i = 1; i <= 8; ++i){
54 char c = getchar(); while(!isdigit(c))c = getchar();
55 exists[i] = c == '1';
56 }ans = INFLL;
57 if(!A && !B){printf("0\n"); continue;}
58 for(int i = 1; i <= 8; ++i)
59 if(exists[i]){
60 if(A * dx[i] < 0 || B * dy[i] < 0)continue;
61 if((!dx[i] && (A || !isInteger((ld)B / dy[i]))) || (!dy[i] && (B || !isInteger((ld)A / dx[i]))))continue;
62 if(!dx[i])ans = min(ans, B / dy[i]);
63 if(!dy[i])ans = min(ans, A / dx[i]);
64 ld v1 = (ld)A / dx[i], v2 = (ld)B / dy[i];
65 if(!isInteger(v1) || !isInteger(v2) || (ll)v1 != (ll)v2)continue;
66 ans = min(ans, (ll)v1);
67 }
68 for(int i = 1; i <= 8; ++i)for(int j = i + 1; j <= 8; ++j)
69 if(exists[i] && exists[j])Check(i, j);
70 for(int i = 2; i <= 8; i += 2){
71 if(!exists[i] || !exists[i == 2 ? 8 : i - 2])continue;
72 for(int j = 1; j <= 8; j += 2){
73 if(!exists[j])continue;
74 A -= dx[j], B -= dy[j];
75 Check(i == 2 ? 8 : i - 2, i, 1);
76 A += dx[j], B += dy[j];
77 }
78 }
79 printf("%lld\n", ans == INFLL ? -1ll : ans);
80 }
81 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
82 return 0;
83}
84
85template < typename T >
86inline T read(void){
87 T ret(0);
88 int flag(1);
89 char c = getchar();
90 while(c != '-' && !isdigit(c))c = getchar();
91 if(c == '-')flag = -1, c = getchar();
92 while(isdigit(c)){
93 ret *= 10;
94 ret += int(c - '0');
95 c = getchar();
96 }
97 ret *= flag;
98 return ret;
99}
update-2023_02_09 初稿