1 #include <bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 inline int read()
5 {
6 int x=0,f=1;char ch=getchar();
7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
8 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
9 return x*f;
10 }
11
12
13 /********************************************************************/
14
15 struct ZKM_MinCostMaxFlow{
16 const static int maxn = 1e5+50;
17 const static int maxE = 1e5+50;
18 const static int INF = 0xfffffff;
19
20 struct Edge{
21 int to, next, cap, flow, cost;
22 Edge(int _to = 0, int _next = 0, int _cap = 0, int _flow = 0, int _cost = 0):
23 to(_to), next(_next), cap(_cap), flow(_flow), cost(_cost){}
24 }edge[maxE*2];
25
26 int head[maxn], tot;
27 int cur[maxn], dis[maxn];
28 bool vis[maxn];
29 int ss, tt, N;
30 int min_cost, max_flow;
31 void init(int N){
32 tot = 0;
33 for(int i = 0;i < N;i++) head[i] = -1;
34 }
35 int addedge(int u, int v, int cap, int cost){
36 edge[tot] = Edge(v, head[u], cap, 0, cost);
37 int rs = tot;
38 head[u] = tot++;
39 edge[tot] = Edge(u, head[v], 0, 0, -cost);
40 head[v] = tot++;
41 return rs;
42 }
43 int aug(int u, int flow){
44 if(u == tt) return flow;
45 vis[u] = true;
46 for(int i = cur[u];i != -1;i = edge[i].next){
47 int v = edge[i].to;
48 if(edge[i].cap > edge[i].flow && !vis[v] && dis[u] == dis[v] + edge[i].cost){
49 int tmp = aug(v, min(flow, edge[i].cap - edge[i].flow));
50 edge[i].flow += tmp;
51 edge[i^1].flow -= tmp;
52 cur[u] = i;
53 if(tmp) return tmp;
54 }
55 }
56 return 0;
57 }
58 bool modify_label(){
59 int d = INF;
60 for(int u = 0;u < N;u++){
61 if(vis[u]){
62 for(int i = head[u];i != -1;i = edge[i].next){
63 int v = edge[i].to;
64 if(edge[i].cap > edge[i].flow && !vis[v]){
65 d = min(d, dis[v]+edge[i].cost - dis[u]);
66 }
67 }
68 }
69 }
70 if(d == INF) return false;
71 for(int i = 0;i < N;i++){
72 if(vis[i]){
73 vis[i] = false;
74 dis[i] += d;
75 }
76 }
77 return true;
78 }
79
80 pair<int, int> mincostmaxflow(int start, int ed, int n){
81 ss = start, tt = ed, N = n;
82 min_cost = max_flow = 0;
83 for(int i = 0;i < n;i++) dis[i] = 0;
84 while(1){
85 for(int i = 0;i < n;i++) cur[i] = head[i];
86 while(1){
87 for(int i = 0;i < n;i++) vis[i] = false;
88 int tmp = aug(ss, INF);
89 if(tmp == 0) break;
90 max_flow += tmp;
91 min_cost += tmp*dis[ss];
92 }
93 if(!modify_label()) break;
94 }
95 return make_pair( max_flow, min_cost );
96 }
97 }solver;
98
99 int gcd(int x, int y){
100 if(y == 0) return x;
101 else return gcd(y, x%y);
102 }
103
104 bool check(int x, int y){
105 if(x == y) return false;
106 if(x < y) swap(x, y);
107 int t = sqrt(x*x-y*y);
108 if(t*t != x*x-y*y) return false;
109 if(gcd(y, t) != 1) return false;
110 return true;
111 }
112
113 int main(){
114 int a, b;
115 a = read(); b = read();
116 solver.init(b*2+5);
117 for(int i = a;i <= b;i++){
118 for(int j = a;j <= b;j++){
119 if(check(i, j)){
120 solver.addedge(i, j+b, 1, -i-j);
121 }
122 }
123 solver.addedge(b*2+1, i, 1, 0); //拆点
124 solver.addedge(i+b, b*2+2, 1, 0); //拆点
125 }
126 pair<int, int> ans = solver.mincostmaxflow(b*2+1, b*2+2, b*2+5);
127 printf("%d %d\n", ans.first/2, -ans.second/2);
128 return 0;
129 }