Problem:
Score: 500 points

Problem Statement

Takahashi will take part in an eating contest. Teams of N members will compete in this contest, and Takahashi's team consists of N players numbered 1 through N from youngest to oldest. The consumption coefficient of Member i is A_i.

In the contest, N foods numbered 1 through N will be presented, and the difficulty of Food i is F_i. The details of the contest are as follows:

A team should assign one member to each food, and should not assign the same member to multiple foods.

It will take x \times y seconds for a member to finish the food, where x is the consumption coefficient of the member and y is the difficulty of the dish.

The score of a team is the longest time it takes for an individual member to finish the food.

Before the contest, Takahashi's team decided to do some training. In one set of training, a member can reduce his/her consumption coefficient by 1, as long as it does not go below 0. However, for financial reasons, the N members can do at most K sets of training in total.

What is the minimum possible score of the team, achieved by choosing the amounts of members' training and allocating the dishes optimally?

Constraints

All values in input are integers.

1 \leq N \leq 2 \times 10^5

0 \leq K \leq 10^{18}

1 \leq A_i \leq 10^6\ (1 \leq i \leq N)

1 \leq F_i \leq 10^6\ (1 \leq i \leq N)

Input

Input is given from Standard Input in the following format:

N K
A_1 A_2 ... A_N
F_1 F_2 ... F_N

Output

Print the minimum possible score of the team.

Sample Input 1

3 5
4 2 1
2 3 1

Sample Output 1

2

They can achieve the score of 2, as follows:

Member 1 does 4 sets of training and eats Food 2 in (4-4) \times 3 = 0 seconds.

Member 2 does 1 set of training and eats Food 3 in (2-1) \times 1 = 1 second.

Member 3 does 0 sets of training and eats Food 1 in (1-0) \times 2 = 2 seconds.

They cannot achieve a score of less than 2, so the answer is 2.

Sample Input 2

3 8
4 2 1
2 3 1

Sample Output 2

0

They can choose not to do exactly K sets of training.

Sample Input 3

11 14
3 1 4 1 5 9 2 6 5 3 5
8 9 7 9 3 2 3 8 4 6 2

Sample Output 3

12

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
#define REP(i,n) for(int i=0,i##_len=(n);i<i##_len;++i)
#define RREP(i,n) for(int i=int(n)-1;i>=0;--i)
#define rep(i,a,b) for(int i=int(a);i<int(b);++i)
#define rrep(i,a,b) for(int i=int(a)-1;i>=int(b);--i)
#define All(x) (x).begin(),(x).end()
#define rAll(x) (x).rbegin(),(x).rend()
#define ITR(i,x) for(auto i=(x).begin();i!=(x).end();++i)
using namespace std;
using Graph = vector<vector<int>>;

typedef long long ll;
typedef pair<ll, ll> P;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
constexpr ll mod = 1e9+7;
constexpr double eps = 1e-9;
const double PI = acos(-1);
void solve();
template<typename T>
bool chmax(T &a,T b){
    if(a<b){
        a=b;
        return true;
    }
    return false;
}
template<typename T>
bool chmin(T &a,T b){
    if(b<a){
        a=b;
        return true;
    }
    return false;
}
P bisearch(ll l,ll r,function<bool(ll)> f){
    while((l+1)<r){
        ll m=(l+r)/2;
        if(f(m)) r=m;
        else l=m;
    }
    return P(l,r);
}
ll SQRT(ll n){if(n==1) return 1;return bisearch(0,n,[n](ll x){return x>n/x;}).first;}
ll roundup(ll n,ll div){
    if(n>0) return (n-1)/div+1;
    else return n/div;    
}
bool square(ll a){ll n=SQRT(a);return a==n*n;}
template<typename T> T npow(T x, ll n){
    T ans = 1;
    while(n != 0){
        if(n&1) ans = ans*x;
        x = x*x;
        n = n >> 1;
    }
    return ans;
}
ll mpow(ll x, ll n){
    ll ans = 1; x%=mod;
    while(n != 0){
        if(n&1) ans = ans*x % mod;
        x = x*x % mod;
        n = n >> 1;
    }
    return ans;
}
ll inv_mod(ll a){return mpow(a,mod-2);}
int digitsum(ll N,int a){
    if(N==0) return 0;
    int ret=0;
    ret+=digitsum(N/a,a)+N%a;
    return ret;
}
ll gcd(ll x,ll y){return y ? gcd(y,x%y) : x;};//xとyの最大公約数
ll lcm(ll x,ll y){return x/gcd(x,y)*y;}//xとyの最小公倍数
void YN(bool flg){std::cout<<(flg?"YES":"NO")<<endl;}
void Yn(bool flg){std::cout<<(flg?"Yes":"No")<<endl;}
void yn(bool flg){std::cout<<(flg?"yes":"no")<<endl;}
P splitint(string n,int a){
    int Len=n.length();
    if(a<0||Len<a) return {-1,-1};
    string left,right;
    if(a!=0) left=n.substr(0,a);
    if(a!=Len) right=n.substr(a);
    return P(stoll(left),stoll(right));
}
ll manhattan(const P &a,const P &b){return llabs(a.first-b.first)+llabs(a.second-b.second);}
bool kaibun(string s){//O(|S|)
    string  sdash=s;
    reverse(All(s));
    return s==sdash;
}
template<class V> 
vector<int> Zalgo(V s){
    vector<int> A(s.size(),0);
    A[0]=s.size();
    int i = 1, j = 0;
    while (i < s.size()) {
        while (i+j < s.size() && s[j] == s[i+j]) ++j;
        A[i] = j;
    if (j == 0) { ++i; continue;}
    int k = 1;
    while (i+k < s.size() && k+A[k] < j) A[i+k] = A[k], ++k;
    i += k; j -= k;
    }
    return A;
}
class Ruiseki{
  private:
    vector<ll> LEFT,RIGHT;
    function<ll(ll,ll)> F;
    int N;
  public:
    Ruiseki(ll INI,const vector<ll> &a,function<ll(ll,ll)> f){
        N=a.size();F=f;
        LEFT.resize(N+1);RIGHT.resize(N+1);
        LEFT[0]=RIGHT[0]=INI;
        REP(i,N){ 
            LEFT[i+1]=F(LEFT[i],a[i]);
            RIGHT[i+1]=F(RIGHT[i],a[N-i-1]);
        }
    }
    ll out(int l,int r){//[l,r)の外の累積
        return F(LEFT[l],RIGHT[N-r]);
    }
};
class mint {
 private:
  ll _num,_mod;
  mint set(ll num){ 
      _num = num ;
      if(_num>=0) _num%=_mod;
      else _num+=(1-(_num+1)/_mod)*_mod; 
      return *this;
  }
  ll _mpow(ll x, ll n){ //x^n(mod) ←普通にpow(x,n)では溢れてしまうため，随時mod計算 2分累乗法だから早い
    ll ans = 1;
    while(n != 0){
        if(n&1) ans = ans*x % _mod;
        x = x*x % _mod;
        n = n >> 1;
    }
    return ans;
  }
  ll imod(ll n){return _mpow(n , _mod-2);}
 public:
  mint(){ _num = 0;_mod=mod; }
  mint(ll num){ _mod = mod; _num = (num+(1LL<<25)*mod) % mod; }
  mint(ll num,ll M){ _mod=M;_num=(num+(1LL<<25)*mod)%_mod; }
  mint(const mint &cp){_num=cp._num;_mod=cp._mod;}
  mint operator= (const ll x){ return set(x); }
  mint operator+ (const ll x){ return mint(_num + (x % _mod) , _mod); }
  mint operator- (const ll x){ return mint(_num - (x % _mod), _mod); }
  mint operator* (const ll x){ return mint(_num * (x % _mod) , _mod); }
  mint operator/ (ll x){ return mint(_num * imod(x) , _mod);}
  mint operator+=(const ll x){ return set(_num + (x % _mod)); }
  mint operator-=(const ll x){ return set(_num - (x % _mod)); }
  mint operator*=(const ll x){ return set(_num * (x % _mod)); }
  mint operator/=(ll x){ return set(_num * imod(x));}
  mint operator+ (const mint &x){ return mint(_num + x._num , _mod); }
  mint operator- (const mint &x){ return mint(_num - x._num , _mod);}
  mint operator* (const mint &x){ return mint(_num * x._num , _mod); }
  mint operator/ (mint x){ return mint(_num * imod(x._num) , _mod);}
  mint operator+=(const mint &x){ return set(_num + x._num); }
  mint operator-=(const mint &x){ return set(_num - x._num); }
  mint operator*=(const mint &x){ return set(_num * x._num); }
  mint operator/=(mint x){ return set(_num * imod(x._num));}

  bool operator<(const mint &x)const{return _num<x._num;}
  bool operator==(const mint &x)const{return _num==x._num;}
  bool operator>(const mint &x)const{return _num>x._num;}

  friend mint operator+(ll x,const mint &m){return mint(m._num + (x % m._mod) , m._mod);}
  friend mint operator-(ll x,const mint &m){return mint( (x % m._mod) - m._num , m._mod);}
  friend mint operator*(ll x,const mint &m){return mint(m._num * (x % m._mod) , m._mod);}
  friend mint operator/(ll x,mint m){return mint(m.imod(m._num) * x , m._mod);}

  explicit operator ll() { return _num; }
  explicit operator int() { return (int)_num; }

  friend ostream& operator<<(ostream &os, const mint &x){ os << x._num; return os; }
  friend istream& operator>>(istream &is, mint &x){ll val; is>>val; x.set(val); return is;}
};
template<typename T> class MAT{
 private:
    int row,col;
    vector<vector<T>> _A;
    MAT set(vector<vector<T>> A){_A = A ; return *this;}
 public:
    MAT(){ }
    MAT(int n,int m){
        if(n<1 || m<0){cout << "err Matrix::Matrix" <<endl;exit(1);}
        row = n;
        col = m?m:n;//m=0のとき単位行列を作る
        REP(i,row){
            vector<T> a(col,0.0);
            _A.push_back(a);
        }
        //  値の初期化
        if(m==0) REP(i,n) _A[i][i]=1.0;
    }
    MAT(const MAT &cp){_A=cp._A;row=cp.row;col=cp.col;}
    T* operator[] (int i){return _A[i].data();}
    MAT operator= (vector<vector<T>> x) {return set(x);}
    MAT operator+ (MAT x) {
        if(row!=x.row || col!=x.col){
            cout << "err Matrix::operator+" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, col);
        REP(i,row) REP(j,col) r[i][j]=_A[i][j]+x[i][j];
        return r;
    }
    MAT operator- (MAT x) {
        if(row!=x.row || col!=x.col){
            cout << "err Matrix::operator-" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, col);
        REP(i,row) REP(j,col) r[i][j]=_A[i][j]-x[i][j];
        return r;
    }
    MAT operator* (MAT x) {
        if(col!=x.row){
            cout << "err Matrix::operator*" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, x.col);
        REP(i,row) REP(j,x.col) REP(k,col) r[i][j]+=_A[i][k]*x[k][j];
        return r;
    }
    MAT operator/ (T a){
        MAT r(row,col);
        REP(i,row) REP(j,col) r[i][j]=_A[i][j]/a;
        return r;
    }
    MAT operator^ (ll n){
        if(row!=col){
            cout << "err Matrix::operator^" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row,0),A=*this;
        while(n){
            if(n&1) r *= A;
            A*=A;
            n>>=1;
        }
        return r;
    }
    MAT operator+= (MAT x) {
        if(row!=x.row || col!=x.col){
            cout << "err Matrix::operator+=" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, col);
        REP(i,row) REP(j,col) r[i][j]=_A[i][j]+x[i][j];
        return set(r._A);
    }
    MAT operator-= (MAT x) {
        if(row!=x.row || col!=x.col){
            cout << "err Matrix::operator-=" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, col);
        REP(i,row) REP(j,col) r[i][j]=_A[i][j]-x[i][j];
        return set(r._A);
    }
    MAT operator*= (MAT x) {
        if(col!=x.row){
            cout << "err Matrix::operator*" <<endl;
            cout << "  not equal matrix size" <<endl;
            exit(0);
        }
        MAT r(row, x.col);
        REP(i,row) REP(j,x.col) REP(k,col) r[i][j]+=_A[i][k]*x[k][j];
        return set(r._A);
    }
    MAT operator/=(T a){
        MAT r(row,col);
        REP(i,row) REP(j,col) r[i][j]=_A[i][j]/a;
        return r;
    }

    friend MAT operator* (T n,MAT x){
        MAT r(x.row,x.col);
        REP(i,x.row) REP(j,x.col) r[i][j]=n*x[i][j];
        return r;
    }
    friend MAT operator* (MAT x,T n){
        MAT r(x.row,x.col);
        REP(i,x.row) REP(j,x.col) r[i][j]=n*x[i][j];
        return r;
    }
    explicit operator vector<vector<T>>(){return _A;}
    friend ostream &operator<<(ostream &os,const MAT &x){ REP(i,x.row) REP(j,x.col) os<<x._A[i][j]<<" \n"[j==x.col-1]; return os;}
    friend istream &operator>>(istream &is,MAT &x){REP(i,x.row) REP(j,x.col) is>>x._A[i][j];return is;}
    int size_row(){return row;}
    int size_col(){return col;}
    MAT transpose(){
        MAT r(col,row);
        REP(i,col) REP(j,row) r[i][j]=_A[j][i];
        return r;
    }
    MAT inverse(){
        T buf;
        MAT<T> inv_a(row,0);
        vector<vector<T>> a=_A;
        //掃き出し法
        REP(i,row){
            buf=1/a[i][i];
            REP(j,row){
                a[i][j]*=buf;
                inv_a[i][j]*=buf;
            }
            REP(j,row){
                if(i!=j){
                    buf=a[j][i];
                    REP(k,row){
                        a[j][k]-=a[i][k]*buf;
                       inv_a[j][k]-=inv_a[i][k]*buf;
                    }
                }
            }
        }
        return inv_a;
    }
    // O( n^3 ).
    int rank() {
        vector<vector<T>> A=_A;
        const int n = row, m = col;
        int r = 0;
        for(int i = 0; r < n && i < m; ++i) {
            int pivot = r;
            for(int j = r+1; j < n; ++j) if(fabs(A[j][i]) > fabs(A[pivot][i])) pivot = j;
            swap(A[pivot], A[r]);
            if(fabs(A[r][i]) < eps) continue;
            for (int k = m-1; k >= i; --k) A[r][k] /= A[r][i];
            rep(j,r+1,n) rep(k,i,m) A[j][k] -= A[r][k] * A[j][i];
            ++r;
        }
        return r;
    }
};
class UnionFind{//UnionFind木
 private:
    vector<int> Parent,es;
    vector<ll> diff_weight;
 public:
    UnionFind(int N){
        es.resize(N,0);
        Parent.resize(N,-1);
        diff_weight.resize(N,0LL);
    }

    int root(int A){
        if(Parent[A]<0) return A;
        else{ 
            int r = root(Parent[A]);
            diff_weight[A] += diff_weight[Parent[A]]; // 累積和をとる
            return Parent[A]=r;
        }
    }
    bool issame(int A,int B){
        return root(A)==root(B);
    }
    ll weight(int x) {
        root(x); // 経路圧縮
        return diff_weight[x];
    }
    ll diff(int x, int y) {
        return weight(y) - weight(x);
    }
    int size(int A){
        return -Parent[root(A)];
    }
    int eize(int A){
        return es[root(A)];
    }
    bool connect(int A,int B){
        A=root(A); B=root(B);
        if(A==B) return false;
        if(size(A)<size(B)) swap(A,B);
        Parent[A]+=Parent[B];
        es[A]+=es[B]+1;
        Parent[B]=A;
        return true;
    }
    void unite(int A,int B){
        A=root(A); B=root(B);
        if(A==B){ 
            es[A]++;
            return;
        }
        if(size(A)<size(B)) swap(A,B);
        Parent[A]+=Parent[B];
        es[A]+=es[B]+1;
        Parent[B]=A;
        return;
    }
    bool merge(int A, int B, ll w) {
        // x と y それぞれについて、 root との重み差分を補正
        w += weight(A); w -= weight(B); 
        A=root(A); B=root(B);
        if(A==B) return false;
        if(size(A)<size(B)) swap(A,B),w=-w;
        Parent[A]+=Parent[B];
        Parent[B]=A;
        // x が y の親になるので、x と y の差分を diff_weight[y] に記録
        diff_weight[B] = w; 
        return true;
    }
};
class Factorial{//階乗とその逆元を求めて計算に利用するクラス
 private:
    vector<ll> fac;
    vector<ll> ifac;
 public:
    
    Factorial(ll N){
        fac.push_back(1);
        REP(i,N) fac.push_back(fac[i]*(i+1)%mod);
        ifac.resize(N+1);
        ifac[N]=inv_mod(fac[N]);
        REP(i,N) ifac[N-1-i]=(ifac[N-i]*(N-i))%mod;
    }

    ll fact(ll a){return fac[a];}
    ll ifact(ll a){return ifac[a];}

    ll cmb(ll a,ll b){
        if(a==0&&b==0) return 1;
        if(a<b||a<0||b<0) return 0;
        ll tmp =ifact(a-b)*ifact(b)%mod;
        return tmp*fac[a]%mod;
    }
    ll per(ll a,ll b){
        if(a==0&&b==0) return 1;
        if(a<b||a<0||b<0) return 0;
        return fac[a]*ifac[a-b]%mod;
    }
};
class SOSU{
 private:
    vector<int> Prime_Number;
    vector<bool> isp;
 public:
    SOSU(int N){
        isp.resize(N+1,true);
        isp[0]=isp[1]=false;
        rep(i,2,N+1) if(isp[i]){
            Prime_Number.push_back(i);
            for(int j=2*i;j<=N;j+=i) isp[j]=false;
        }
    }
    int operator[](int i){return Prime_Number[i];}
    int size(){return Prime_Number.size();}
    int back(){return Prime_Number.back();}
    bool isPrime(int q){return isp[q];}
};
class Divisor{//素因数分解をしてから約数列挙、分解結果はＰ(底,指数)でpfacにまとめている
  private:
    vector<ll> F;
    vector<P> pfactorize;
  public:
    Divisor(ll N){
        for(ll i = 1; i * i <= N; i++) {
            if(N % i == 0) {
                F.push_back(i);
                if(i * i != N) F.push_back(N / i);
            }
        }
        sort(begin(F), end(F));
		SOSU p(SQRT(N)+1);
    	REP(i,p.size()){
    		pfactorize.push_back(P(p[i],0));
    		while(N%p[i]==0){
    			N/=p[i];
    			pfactorize.back().second++;
    		}
            if(pfactorize.back().second==0) pfactorize.pop_back();
    	}
    	if(N>1) pfactorize.push_back(P(N,1));
    }
    int size(){return F.size();}
    vector<P> pfac(){return pfactorize;}
    ll operator[](int k){return F[k];}
};
struct Solutions{
    ll napsack(int kinds,int MAX_W,const vl &weight,const vl &cost){
        vector<vector<ll>> dp(kinds+1,vector<ll>(MAX_W+1,0));
        REP(i,kinds) REP(j,MAX_W+1){
            if(j<weight[i]) dp[i+1][j]=dp[i][j];
            else dp[i+1][j]=max(dp[i][j],dp[i][j-weight[i]]+cost[i]);
        }
        return dp[kinds][MAX_W];
    }
    ll cost_based_napsack(int kinds,int MAX_W,const vl &weight,const vl &cost){
        int MAX_V=0;
        REP(i,kinds) MAX_V=max(MAX_V,(int)cost[i]);
        vvl dp(kinds+1,vl(kinds*MAX_V+1,1LL<<58));
        dp[0][0] = 0;
        REP(i,kinds) REP(j,kinds*MAX_V+1){
            if(j<cost[i]) dp[i+1][j]=dp[i][j];
            else dp[i+1][j] = min(dp[i][j],dp[i][j-cost[i]]+weight[i]);
        }
        int res=0;
        REP(i,kinds*MAX_V+1) if(dp[kinds][i]<=MAX_W) res=i;
        return res;
    }
    ll unlimited_napsack(int kinds,int MAX_W,const vl &weight,const vl &cost){
        vector<vector<ll>> dp(kinds+1,vector<ll>(MAX_W+1,0));
        REP(i,kinds) REP(j,MAX_W+1){
            if(j<weight[i]) dp[i+1][j]=dp[i][j];
            else dp[i+1][j]=max(dp[i][j],dp[i+1][j-weight[i]]+cost[i]);
        }
        return dp[kinds][MAX_W];
    }
    ll huge_napsack(int kinds,ll MAX_W,const vl &weight,const vl &cost){
        int n2=kinds/2;
        vector<P> ps(1<<(kinds/2));
        REP(i,1<<n2){
            ll sw=0,sv=0;
            REP(j,n2){
                if(i>>j&1){
                    sw += weight[j];
                    sv += cost[j];
                }
            }
            ps[i] = P(sw,sv);
        }
        sort(ps.begin(),ps.begin() + (1<<n2) );
        int m=1;
        rep(i,1,1<<n2){
            if(ps[m-1].second<ps[i].second) ps[m++] = ps[i];
        }

        ll res=0;
        REP(i,1<<(kinds-n2)){
            ll sw=0,sv=0;
            REP(j,kinds-n2){
                if((i>>j)&1){
                    sw += weight[n2+j];
                    sv += cost[n2+j];
                }
            }
            if(sw<=MAX_W){
                ll tv = (lower_bound(ps.begin(),ps.begin()+m,P(MAX_W-sw,LLONG_MAX))-1)->second;
                res = max(res,sv+tv);
            }
        }
        return res;
    }
    ll choose_MonN(int N,int M,const vl &cost){
        vvl dp(N+1,vl(M+1,-1LL<<58));
        REP(i,N+1) dp[i][0]=0;
        REP(i,N) REP(j,M){
            if(j>i) break;
            dp[i+1][j+1]=max(dp[i][j+1],dp[i][j]+cost[i]);
        }
        return dp[N][M];
    }
    ll Partition_Func(int n,int k){
        vector<vector<ll>> dp(k+1,vector<ll> (n+1,0));
        dp[0][0]=1;
        rep(i,1,k+1) REP(j,n+1){
            if(j-i>=0) dp[i][j]=(dp[i][j-i]+dp[i-1][j]);
            else dp[i][j]=dp[i-1][j];
        }
        return dp[k][n];
    }
    int LCS(string s,string t){
        int n=s.length(),m=s.length();
        vector<vector<int>> dp(n+1,vector<int>(m+1));
        REP(i,n) REP(j,m){
            if (s[i] == t[j]) dp[i+1][j+1] = dp[i][j] + 1;
            else dp[i+1][j+1] = max(dp[i][j+1], dp[i+1][j]);
        }
        return dp[n][m];
    }
    int LIS(const vector<ll> a){
        int n=a.size();
        ll INF=1LL<<50;
        vector<ll> dp(n+1,INF);
        REP(i,n) *lower_bound(All(dp),a[i])=a[i];
        int k=lower_bound(All(dp),INF)-dp.begin();
        return k;
    }
    
    int max_flow(int s,int t,const vector<vector<P>> &g){
        struct edge_{int to,cap, rev;};
        vector<bool> used(g.size(),false);
        vector<vector<edge_>> G(g.size());
        REP(i,g.size()) REP(j,g[i].size()){
            int from = i, to = g[i][j].second;
            int cap = g[i][j].first;
            G[from].push_back((edge_){to,cap,(int)G[to].size()});
            G[to].push_back((edge_){from,0,(int)G[from].size()-1});
        }
        auto dfs = [&](auto&& f,int v,int t,int fl)->int{
            if(v==t) return fl;
            used[v] = true;
            REP(i,G[v].size()){
                edge_ &e = G[v][i];
                if(!used[e.to] && e.cap>0){
                    int d = f(f, e.to,t,min(fl,e.cap));
                    if(d>0){
                        e.cap -= d;
                        G[e.to][e.rev].cap += d;
                        return d;
                    }
                }
            }
            return 0;
        };
        int flow=0;
        while(1){
            used.assign(used.size(),false);
            int f = dfs(dfs,s,t,INT_MAX);
            if(f==0) return flow;
            flow += f;
        }
    }
    int bipartite_matching_calculate(const Graph &g){
        int V = g.size();
        vi match(V,-1);
        vector<bool> used(V,false);
        auto dfs = [&](auto&& f,int v)->bool{
            used[v]=true;
            REP(i,g[v].size()){
                int u = g[v][i], w = match[u];
                if(w<0 || !used[w] && f(f,w)){
                    match[v]=u;
                    match[u]=v;
                    return true;
                }
            }
            return false;
        };
        int res=0;
        REP(v,V){
            if(match[v] < 0){
                used.assign(V,false);
                if(dfs(dfs,v)) res++;
            }
        }
        return res;
    }
    int bipartite_matching(int l,int r,function<bool(int,int)> F){
        int V = l+r;
        Graph G(V);
        REP(i,l) REP(j,r) if(F(i,j)){
            G[i].push_back(l+j);
            G[l+j].push_back(i);
        }
        return bipartite_matching_calculate(G);
    }
    ll dinic(int s,int t,const vector<vector<P>> &graph){
        struct max_flow {
            struct edge_ { int to;ll cap;int rev; };
            int V;
            vector<vector<edge_>> G;
            vector<int> itr, level;
            max_flow(int V) : V(V) { G.assign(V,vector<edge_>()); }

            void add_edge(int from, int to, ll cap) {
                G[from].push_back((edge_) {to, cap, (int) G[to].size()});
                G[to].push_back((edge_) {from, 0, (int) G[from].size()-1});
            }
            void bfs(int s) {
                level.assign(V,-1);
                queue<int> q;
                level[s] = 0; q.push(s);
                while (!q.empty()) {
                    int v = q.front(); q.pop();
                    for(auto &e: G[v]) if(e.cap > 0 and level[e.to] < 0) {
                            level[e.to] = level[v] + 1;
                            q.push(e.to);
                    }
                }
            }

            ll dfs(int v, int t, ll f) {
                if(v == t) return f;
                for(int& i=itr[v]; i < (int) G[v].size(); ++i) {
                    edge_& e = G[v][i];
                    if (e.cap > 0 and level[v] < level[e.to]) {
                        int d = dfs(e.to, t, min(f, e.cap));
                        if (d > 0) {
                            e.cap -= d;
                            G[e.to][e.rev].cap += d;
                            return d;
                        }
                    }
                }
                return 0;
            }

            int run(int s, int t) {
                int ret = 0, f;
                while(bfs(s), level[t] >= 0) {
                    itr.assign(V,0);
                    while ((f = dfs(s, t, 1LL<<59)) > 0) ret += f;
                }
                return ret;
            }
        };
        max_flow d(graph.size());
        REP(i,graph.size()) for(auto e:graph[i]){
            d.add_edge(i,e.second,e.first);
        }
        return d.run(s,t);
    }
};
struct compress{
    map<ll,int> zip;
    vector<ll> unzip;
    compress(vector<ll> x){
        unzip=x;
        sort(All(x));
        x.erase(unique(All(x)),x.end());
        REP(i,x.size()){
            zip[x[i]]=i;
        }
    }
    int operator[](int k){return zip[unzip[k]];}
};
struct edge{
    int from;int to;ll cost;
    void push(int a,int b,int c){
        from=a;to=b;cost=c;
    }
    bool operator<(const edge& y) const{
        if(cost!=y.cost) return cost<y.cost;
        else if(to!=y.to) return to<y.to;
        else return from<y.from;}
    bool operator>(const edge& y) const{
        if(cost!=y.cost) return cost>y.cost;
        else if(to!=y.to) return to>y.to;
        else return from>y.from;}
    bool operator==(const edge& y) const{return *this==y;}
};
class lca {
  public:
    const int n = 0;
    const int log2_n = 0;
    std::vector<std::vector<int>> parent;
    std::vector<int> depth;

    lca() {}

    lca(const Graph &g, int root)
        : n(g.size()), log2_n(log2(n) + 1), parent(log2_n, std::vector<int>(n)), depth(n) {
        dfs(g, root, -1, 0);
        for (int k = 0; k + 1 < log2_n; k++) {
            for (int v = 0; v < (int)g.size(); v++) {
                if (parent[k][v] < 0)
                    parent[k + 1][v] = -1;
                else
                    parent[k + 1][v] = parent[k][parent[k][v]];
            }
        }
    }

    void dfs(const Graph &g, int v, int p, int d) {
        parent[0][v] = p;
        depth[v] = d;
        REP(j,g[v].size()) {
            if (g[v][j] != p) dfs(g, g[v][j], v, d + 1);
        }
    }

    int get(int u, int v) {
        if (depth[u] > depth[v]) std::swap(u, v);
        for (int k = 0; k < log2_n; k++) {
            if ((depth[v] - depth[u]) >> k & 1) {
                v = parent[k][v];
            }
        }
        if (u == v) return u;
        for (int k = log2_n - 1; k >= 0; k--) {
            if (parent[k][u] != parent[k][v]) {
                u = parent[k][u];
                v = parent[k][v];
            }
        }
        return parent[0][u];
    }
};
template<typename T> class SegmentTree{
  private:
    typedef function<T(T,T)> F;
    int n;
    T d0;
    vector<T> vertex;
    F f;
    F g;
  public:
    SegmentTree(int _n,F f,F g,T d):d0(d),f(f),g(g){
        init(_n);
    }
    void init(int _n){
        n=1;
        while(n<_n) n*=2;
        vertex.resize(2*n-1,d0);
    }
    void update(int i,T x){
        int k=i+n-1;
        vertex[k]=g(vertex[k],x);
        while(k>0){
            k=(k-1)/2;
            vertex[k]=f(vertex[2*k+1],vertex[2*k+2]);
        }
        return;
    }
    T query(int l,int r){
        T vl=d0,vr=d0;
        l+=n-1;
        r+=n-1;
        for(;l<=r;l/=2,r=r/2-1){
            if(l%2==0) vl=f(vl,vertex[l]);
            if(r&1) vr=f(vr,vertex[r]);
        }
        return f(vl,vr);
    }
};
template <typename T,typename E>
struct LazySegmentTree{
  using F = function<T(T,T)>;
  using G = function<T(T,E)>;
  using H = function<E(E,E)>;
  int n,height;
  F f;
  G g;
  H h;
  T ti;
  E ei;
  vector<T> dat;
  vector<E> laz;
  LazySegmentTree(F f,G g,H h,T ti,E ei):
    f(f),g(g),h(h),ti(ti),ei(ei){}
  
  void init(int n_){
    n=1;height=0;
    while(n<n_) n<<=1,height++;
    dat.assign(2*n,ti);
    laz.assign(2*n,ei);
  }
  void build(const vector<T> &v){
    int n_=v.size();
    init(n_);
    for(int i=0;i<n_;i++) dat[n+i]=v[i];
    for(int i=n-1;i;i--)
      dat[i]=f(dat[(i<<1)|0],dat[(i<<1)|1]);
  }
  inline T reflect(int k){
    return laz[k]==ei?dat[k]:g(dat[k],laz[k]);
  }
  inline void eval(int k){
    if(laz[k]==ei) return;
    laz[(k<<1)|0]=h(laz[(k<<1)|0],laz[k]);
    laz[(k<<1)|1]=h(laz[(k<<1)|1],laz[k]);
    dat[k]=reflect(k);
    laz[k]=ei;
  }
  inline void thrust(int k){
    for(int i=height;i;i--) eval(k>>i);
  }
  inline void recalc(int k){    
    while(k>>=1)
      dat[k]=f(reflect((k<<1)|0),reflect((k<<1)|1));
  }
  void update(int a,int b,E x){
    thrust(a+=n);
    thrust(b+=n-1);
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1){
      if(l&1) laz[l]=h(laz[l],x),l++;
      if(r&1) --r,laz[r]=h(laz[r],x);
    }
    recalc(a);
    recalc(b);
  }
  void set_val(int a,T x){
    thrust(a+=n);
    dat[a]=x;laz[a]=ei;
    recalc(a);
  }
  T query(int a,int b){
    thrust(a+=n);
    thrust(b+=n-1);
    T vl=ti,vr=ti;
    for(int l=a,r=b+1;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,reflect(l++));
      if(r&1) vr=f(reflect(--r),vr);
    }
    return f(vl,vr);
  }
};
struct GP{
    double x,y;
    GP(double X=0,double Y=0):x(X),y(Y){}
    GP(const GP &cp){
        x=cp.x;y=cp.y;
    }
    GP& set(double X,double Y){
        x=X;y=Y;
        return *this;
    }
    GP& operator=(const GP &p){return set(p.x , p.y);}
    GP operator+(const GP &p)const{return GP(x+p.x , y+p.y);}
    GP operator-(const GP &p)const{return GP(x-p.x , y-p.y);}
    GP operator*(double s)const{return GP(x*s,y*s);}
    GP operator/(double s)const{return GP(x/s,y/s);}
    friend GP operator*(double s,const GP &r){return GP(r.x*s,r.y*s);}
    friend GP operator/(double s,const GP &r){return GP(r.x/s,r.y/s);}
    double operator*(GP p)const{return dot(p);}
    double operator^(GP p)const{return cross(p);}
    GP& operator+=(const GP &p){return set(x+p.x , y+p.y);}
    GP& operator-=(const GP &p){return set(x-p.x , y-p.y);}
    GP& operator*=(double s){return set(x*s,y*s);}
    GP& operator/=(double s){return set(x/s,y/s);}
    double dot(const GP &p)const{return x*p.x + y*p.y;} 
    double cross(const GP &p)const{return x*p.y-p.x*y;}
    int ort()const{
        if(fabs(x)<eps && fabs(y)<eps) return 0;
        if(y>0) return (x>0)?1:2;
        else return (x<=0)?3:4;
    }
    bool operator<(const GP &p)const{
        int o=ort(),po=p.ort();
        if(o!=po) return o<po;
        else{
            double cr=cross(p);
            if(cr==0){
                double d=norm(),pd=p.norm();
                return d<pd;
            }
            return cr>0;
        }
    }
    friend istream& operator>>(istream &is, GP &x){double valX,valY; is>>valX>>valY; x.set(valX,valY); return is;}
    friend ostream& operator<<(ostream &os, const GP &v){ os << v.x<<" "<<v.y<<endl; return os; }
    double norm2()const{return x*x+y*y;}
    double norm()const{return sqrt(norm2());}
    double rad()const{
        if(x==0){
            if(y>0) return PI/2.0;
            if(y==0) return -1.0;
            if(y<0) return -PI/2.0;
        }else{
            if(y==0){
                if(x<0) return PI;
                if(x>0) return 0.0;
            }
            else return atan2(y,x);
        }
    }
    void rotate(double theta){
        double X=x,Y=y;
        x=cos(theta)*X-sin(theta)*Y;
        y=sin(theta)*X+cos(theta)*Y;
    }
};
struct Line{
    GP A,B;
    Line(GP p1=GP(0,0),GP p2=GP(1,1)):A(p1),B(p2){}
    double len()const{return (B-A).norm();}
    GP shortest_point(const GP &x)const{
        double a=B.x-A.x,b=B.y-A.y;
        double t=-(a*(A.x-x.x)+b*(A.y-x.y))/(a*a+b*b);
        return GP(a*t+A.x,b*t+A.y);
    }
    double dist(const GP &x)const{
        return (x-shortest_point(x)).norm();
    }
    bool online(const GP &x)const{
        return ((B-A)^(x-A))==0&&(x-A).norm()<=len()&&(x-B).norm()<=len();
    }
    
    friend istream& operator>>(istream &is, Line &x){GP X,Y; is>>X>>Y;x.A=X;x.B=Y;return is;}
    friend ostream& operator<<(ostream &os, const Line &x){ os << x.A << x.B; return os; }
};
struct Triangle{
    GP a,b,c;
    Triangle(GP p1=GP(0,0),GP p2=GP(1,0),GP p3=(0,1)):a(p1),b(p2),c(p3){}

    double A()const{double res=fabs((b-a).rad()-(c-a).rad());if(res>=PI) res-=PI;return res;}
    double B()const{double res=fabs((a-b).rad()-(c-b).rad());if(res>=PI) res-=PI;return res;}
    double C()const{double res=fabs((a-c).rad()-(b-c).rad());if(res>=PI) res-=PI;return res;}
    Line AB()const{return Line(a,b);}
    Line BC()const{return Line(b,c);}
    Line CA()const{return Line(c,a);}

    GP G()const{return (a+b+c)/3;}
    GP O()const{return (sin(2*A())*a+sin(2*B())*b+sin(2*C())*c)/(sin(2*A())+sin(2*B())+sin(2*C()));}
    double R()const{return a.norm()/(2*sin(A()));}
    GP I()const{return (a.norm()*a+b.norm()*b+c.norm()*c)/(a.norm()+b.norm()+c.norm());}
    double r()const{return 2*area()/((a-b).norm()+(b-c).norm()+(c-a).norm());}
    GP H()const{return (tan(A())*a+tan(B())*b+tan(C())*c)/(tan(A())+tan(B())+tan(C()));}
    double AH()const{return 2*R()*cos(A());}
    double BH()const{return 2*R()*cos(B());}
    double CH()const{return 2*R()*cos(C());}
    double area()const{return ((b-a)^(c-a))/2;}

    bool inside(const GP &x)const{
        return ((b-a)^(x-a))*((c-a)^(x-a))<0&&
               ((a-b)^(x-b))*((c-b)^(x-b))<0&&
               ((a-c)^(x-c))*((b-c)^(x-c))<0;
    }
    bool online(const GP &x)const{return AB().online(x)||BC().online(x)||CA().online(x);}
    bool outside(const GP &x)const{return (!inside(x)&&!online(x));}

    friend istream& operator>>(istream &is, Triangle &x){GP X,Y,Z; is>>X>>Y>>Z; x.a=X;x.b=Y;x.c=Z;return is;}
    friend ostream& operator<<(ostream &os, const Triangle &v){ os << v.a << v.b; return os; }
};
struct rational {
  ll p, q;
  void normalize() { // keep q positive
    if (q < 0) p *= -1, q *= -1;
    ll d = gcd(p < 0 ? -p : p, q);
    if (d == 0) p = 0,  q = 1;
    else        p /= d, q /= d;
  }
  rational(ll p, ll q = 1) : p(p), q(q) {
    normalize();
  }
  rational &operator+=(const rational &a){p = a.q * p + a.p * q; q = a.q * q; normalize();return *this;}
  rational &operator-=(const rational &a){p = a.q * p - a.p * q; q = a.q * q; normalize();return *this;}
  rational &operator*=(const rational &a){p *= a.p; q *= a.q;normalize();return *this;}
  rational &operator/=(const rational &a){p *= a.q; q *= a.p; normalize();return *this;}
  rational &operator-(){p *= -1;return *this;}
  friend rational operator+(const rational &a, const rational &b){return rational(a) += b;}
  friend rational operator*(const rational &a, const rational &b){return rational(a) *= b;}
  friend rational operator-(const rational &a, const rational &b){return rational(a)-=b;}
  friend rational operator/(const rational &a, const rational &b){return rational(a) /= b;}
  friend bool operator<(const rational &a, const rational &b){ // avoid overflow 
    return (long double) a.p * b.q < (long double) a.q * b.p;
  }
  friend bool operator<=(const rational &a, const rational &b){return !(b < a);}
  friend bool operator>(const rational &a, const rational &b){return b < a;}
  friend bool operator>=(const rational &a, const rational &b){return !(a < b);}
  friend bool operator==(const rational &a, const rational &b){return !(a < b) && !(b < a);}
  friend bool operator!=(const rational &a, const rational &b){return (a < b) || (b < a);}
  friend ostream& operator<<(ostream &os, const rational &x){ printf("%.16f",(double)x.p/(double)x.q); return os; }
  friend istream& operator>>(istream &is, rational &x){is>>x.p>>x.q; x.normalize(); return is;}
};

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    solve();
    return 0;
}


void solve(){
    int N;cin>>N;
    ll K;cin>>K;
    vector<ll> A(N);
    ll M=0;
    REP(i,N){
        cin>>A[i];
        chmax(M,A[i]);
    }
    vector<ll>  F(N);
    REP(i,N) cin>>F[i];
    sort(rAll(A));sort(All(F));
    ll l=-1,r=1LL<<50;
    while(l+1<r){
        ll m=(l+r)/2;
        ll cost=0;
        REP(i,N){
            cost+=A[i]-m/F[i];
        }
        if(cost>K) l=m;
        else r=m;
    }
    cout<<r<<endl;
}