1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define st first
#define nd second
typedef long long ll;
typedef long double ld;
const ll I = 1000LL * 1000LL * 1000LL * 1000LL * 1000LL * 1000LL;
const ll M = 1000LL * 1000LL * 1000LL + 7LL;
const int N = 40 * 1000 + 7;
int tab1[N], tab2[N];
ll ans[N], il[N], last[N];
vector<int> inc[N];

void DoInc(int n)
{
    for(int i = 2; i <= n; ++i)
        for(int j = i + 2; j <= n; j += i)
            inc[j].pb(i + 1);
}

inline ll F(ll a, ll b)
{
    if(a > b) return 0LL;
    return (((a + b) * (b - a + 1)) / 2LL) % M;
}

inline int Il(int n, int k)
{
    return max(0, (n - k + (k - 2)) / (k - 1));
}

void Upd(ll tim, int j, int n2)
{
    int p = il[j], k = il[j - 1] - 1;
    if(k != -1) p = max(p, 1);
    k = min(k, n2);
    //cout << tim << " " << "w: " << j << " " << p << " " << k << "\n";
    ans[j] += (tim - last[j]) * F(n2 - k + 1, n2 - p + 1);
    ans[j] %= M;
    last[j] = tim;
}

void DoCnt(int n1, int n2)
{
    for(int i = 1; i < n1; ++i)
    {
        int cur = 1;
        for(int j = 1; j <= n1 - i + 1; ++j)
        {
            last[j] = i;
            il[j] = 0;
        }
        for(int j = i + 1; j <= n1; ++j)
        {
            il[1] = j - i + 1;
            ++cur;
            if(cur > 2)
            {
                Upd(j - 1, 3, n2);
                ++il[2];
            }
            Upd(j, 2, n2);
            for(int k = 0; k < (int)inc[cur].size(); ++k)
            {
                Upd(j - 1, inc[cur][k], n2);
                Upd(j - 1, inc[cur][k] + 1, n2);
            }
            for(int k = 0; k < (int)inc[cur].size(); ++k)
                ++il[inc[cur][k]];

            if((tab1[j - 1] < tab1[j]) ^ (tab1[j] < tab1[j + 1]))
                cur = 1;
        }
        for(int j = 3; j <= n1 - i + 1; ++j)
            Upd(n1, j, n2);
    }
}

void Solve()
{
    int n1, n2;
    cin >> n1 >> n2;
    DoInc(max(n1, n2));
    for(int i = 1; i <= n1; ++i)
        cin >> tab1[i];
    for(int i = 1; i <= n2; ++i)
        cin >> tab2[i];
    DoCnt(n1, n2);
    for(int i = 1; i <= max(n1, n2); ++i)
        swap(tab1[i], tab2[i]);
    DoCnt(n2, n1);
    for(int i = 1; i <= max(n1, n2); ++i)
        swap(tab1[i], tab2[i]);

    for(int i = 1; i <= min(n1, n2); ++i)
        ans[2] += ((ll)(n1 - i + 1) * (ll)(n2 - i + 1)) % M;
    //Count(1, 7, 1);
    for(int i = 1; i <= n1 + n2; ++i)
    {
        ans[i] %= M;
        cout << ans[i] << " ";
    }
    cout << "\n";
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    //int t; cin >> t;
    //while(t--)
        Solve();

    return 0;
}