Pagini recente »
Clasament 2017-10-19-clasa-5-tema-11
|
Istoria paginii runda/2021-01-15-clasa-6-tema-19
|
Istoria paginii runda/2023-09-19-clasa-6-tema-2
|
Istoria paginii runda/2018-01-25-clasa-5-tema-22
|
Cod sursă (job #786116)
Cod sursă (job
#786116)
// Author: Tanasescu Andrei-Rares
#include <iostream>
#include <fstream>
using namespace std;
ifstream fin ("dejavu.in");
ofstream fout ("dejavu.out");
typedef long long ll;
const int Nmax=5e3+5, inf=1e9+5, MOD=1e9+7;
int n, q;
// dp[i][j] = modalitatea de a continua un prefix ce are i litere singuratice
// si j perechi de litere
// lungimea prefixului = i+j*2
int dp[Nmax][Nmax/2];
int fr[Nmax], aib1[Nmax], aib2[Nmax];
inline void update(int aib[], int pos, int val){
while (pos<Nmax){
aib[pos]+=val;
pos+=pos&-pos;
}
}
inline int query(int aib[], int pos){
int sum=0;
while (pos>0){
sum+=aib[pos];
pos-=pos&-pos;
}
return sum;
}
inline void clr(int aib[]){
for (int i=1; i<Nmax; i++)
aib[i]=0;
}
int main()
{
fin>>n>>q;
// initializare dp
for (int j=0; j*2<=n; j++){
int i=n-j*2;
dp[i][j]=1;
}
// build dp
for (int l=n-1; l>=0; l--)
for (int j=0; j*2<=l; j++){
int i=l-j*2;
dp[i][j]=(ll)dp[i+1][j]*(n-i-j)%MOD;
if (i!=0)
dp[i][j]=(dp[i][j]+(ll)dp[i-1][j+1]*i)%MOD;
}
// answer queries
while (q--){
int nr, cnt1=0, cnt2=0, crt1, crt0;
ll sol=0;
for (int i=0; i<n; i++){
fin>>nr;
crt1=query(aib1, nr-1);
crt0=nr-1-crt1-query(aib2, nr-1);
sol=(sol+(ll)crt0*dp[cnt1+1][cnt2])%MOD;
if (cnt1!=0)
sol=(sol+(ll)crt1*dp[cnt1-1][cnt2+1])%MOD;
fr[nr]++;
if (fr[nr]==1){
cnt1++;
update(aib1, nr, 1);
}
else{
cnt2++;
cnt1--;
update(aib1, nr, -1);
update(aib2, nr, 1);
}
}
fout<<sol<<'\n';
for (int i=1; i<=n; i++)
fr[i]=0;
clr(aib1);
clr(aib2);
}
return 0;
}