n! 拆分因子比较好的方法。
二分可行最大值。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define rep(i , n) for(int i = 0 ;i<(int)n;i++)
#define rep1(i,x,y) for(int i = (int)x ; i<=(int)y;i++)
const int N = 10100;
int M = 1359;
int vis[N], pos[N];
vector<int> pri;
void init()
{
memset(vis,0,sizeof(vis));
for(int i =2 ; i<N; i++) if(!vis[i])
for(int j = i ; j < N ; j+=i)
vis[j] = i;
for(int i =2 ; i<N ; i++)
{
if(vis[i] == i)
{
pri.push_back(i);
pos[i] = pri.size() - 1;
}
}
M = pri.size();
}
int a[N] , b[N];
int cal(int f , int n)
{
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < M; j++)
{
int tn = b[i];
if(tn < pri[j]) break;
while(tn)
{
a[j] += (tn / pri[j]) * f;
tn /= pri[j];
if(a[j] < 0) return 0;
}
}
}
return 1;
}
int n,m;
int ans[N][2] , tag = 0;
bool judge(int x)
{
for(int j = 0; j < M; j++)
{
b[j] = 0;
int tn = x;
if(tn < pri[j]) break;
while(tn)
{
b[j] += (tn / pri[j]);
tn /= pri[j];
}
if(a[j] < b[j]) return 0;
}
return 1;
}
int c[N];
void get2(int u)
{
int min_ = 1e9 ;
for(int i = 0; i<M ; i++)
{
c[i] = 0;
int x = u , p = pri[i];
if(x < p) break;
while(x)
{
c[i] += x / p;
x /= p;
}
min_ = min(min_ , a[i] / c[i]);
}
for(int i = 0 ; i<M ; i++)
{
if(pri[i] > u) break;
a[i] -= c[i] * min_;
}
ans[tag][0] = u;
ans[tag][1] = min_;
++tag;
}
void get()
{
int cnt = 0 ;
for(; a[0] > 0;)
{
int x = 2 , y = 10007;
while(x < y)
{
int mid = (x + y)>>1;
if(judge(mid)) x = mid + 1;
else y = mid;
}
get2(x - 1);
}
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n , &m);
memset(a , 0 , sizeof(a));
memset(b , 0 , sizeof(b));
rep1(i , 1 , n){
scanf("%d",&b[i]);
}
cal(1 , n);
memset(b , 0 , sizeof(b));
rep1(i , 1 , m)
{
scanf("%d",&b[i]);
}
if(cal(-1 , m) == 0)
{
printf("-1\n");
continue;
}
tag = 0;
get();
printf("%d\n",tag);
for(int i = 0 ; i<tag ; i++)
{
printf("%d %d\n",ans[i][0] , ans[i][1]);
}
}
return 0;
}
/*
99
1
1
10000
1
*/