#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
typedef pair<long long,long long>pll;
ll dp[55][2000];//dp[i][j]表示长度为i的排列中逆序对为j的排列数
ll s[55][2000];//s[i][j]表示dp[i][0]到dp[i][j]的和
ll ans[55];//ans[i]代表长度为i的后半段满足条件的种数
ll n,p;
void init(){
    ll i,j;
    dp[0][0]=1;
    for(i=0;i<=n*(n-1)/2;i++) s[0][i]=1;
    for(i=1;i<=n;i++){//枚举第一个出现不同的位置
        for(j=0;j<=n*(n-1)/2;j++){
            if(j-i>=0) dp[i][j]=(s[i-1][j]-s[i-1][j-i]+p)%p;
            else dp[i][j]=s[i-1][j]%p;
            if(!j) s[i][j]=dp[i][j]%p;
            else s[i][j]=(s[i][j-1]+dp[i][j])%p;
        }
    }
}
void solve(){
    ll i,j,k,q,t;
    cin>>n>>p;
    init();
    for(i=1;i<=n;i++){//枚举后半段长度
        for(j=1;j<=i;j++){//枚举p
            for(k=j+1;k<=i;k++){//枚举q
                for(q=0;q<=i*(i-1)/2;q++){//统计逆序对数大于p-q的排列数
                    t=q-k+j;
                    if(t<=0) continue;
                    ans[i]=(ans[i]+dp[i-1][q]*s[i-1][t-1]%p)%p;
                }
            }
        }
    }
    for(i=2;i<=n;i++) ans[i]=(ans[i]+1ll*ans[i-1]*i)%p;//考虑前半段排列情况，将i-1归到i：C（i，1）
    printf("%lld",ans[n]);
}
int main(void){
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }
}