题意:给你一个公式F(x) = 1 × (1! + x) + 2 × (2! + x) + · · · + x × (x! + x),n个pi,计算F(p1) + F(p2) + · · · + F(pn),然后结果模m。
康拓展开:X=a[n]∗(n−1)!+a[n−1]∗(n−2)!+...+a[i]∗(i−1)!+...+a[1]∗0!
含义:设有n个数(1,2,3,4,…,n),可以有组成不同(n!种)的排列组合,康托展开表示的就是是当前排列组合在n个不同元素的全排列中的名次。
a[i]的含义:a[i]为整数,并且0 <= a[i] <= i, 0 <= i < n, 表示当前未出现的的元素中排第几个(是从0开始算的)。例如:3412,a[3]=2,a[4]=2,a[1]=0,a[2]=0。
特别:对于一个序列来说,例如3个数(1,2,3)来说,会发现序列(1 2 3)的排名为1,序列(3 2 1)的排名为3!。序列(1,2,· · ·,n)排名为0,序列(n,n-1,· · ·,1)的排名为n!-1(因为计算的排名是从0开始算的所以要-1)。
思路:把F(x) = 1 × (1! + x) + 2 × (2! + x) + · · · + x × (x! + x)转换成F(x)=1∗1!+2∗2!+3∗3!+ · · · +x∗x!+(1+2+3 +· · · +x)∗x,然后就会发现前面的式子1∗1!+2∗2!+3∗3!+ · · · +x∗x!其实是序列(x+1 x x-1 · · ·1)的康拓展开式,会发现它是最后一名。因为计算的排名是从0开始算的,所以上述的序列的康拓展开排名为(x+1)!-1。于是F(x)的函数表达就转换成F(x)=(x+1)!−1+(1+x)*x*x/2了。
还有就是关于大阶乘取模的问题,如果n>=mod,那么n的阶乘的因子中一定有mod,n的阶乘模mod一定等于0。
代码:
#include <algorithm>
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=1e5+5;
const int maxm=1e7+10;
int n,mod;
long long int num[maxn];//记录数字
long long int sum[maxm];//记录阶乘
int main(){
scanf("%d%d",&n,&mod);
for(int i=0;i<n;i++){
scanf("%lld",&num[i]);
}
sum[1]=1;
for(int i=2;i<=mod;i++){//计算阶乘
sum[i]=(i*sum[i-1])%mod;
}
long long int ans=0;
for(int i=0;i<n;i++){
long long int tmp=0;
//分奇数偶数是因为要除2
if(num[i]%2){//奇数
tmp=(num[i]+1)/2%mod*(num[i]%mod)%mod*(num[i]%mod)%mod;
}
else {//偶数
tmp=num[i]/2%mod*(num[i]%mod)%mod*((num[i]+1)%mod)%mod;
}
if(num[i]+1<mod)
tmp=(tmp+sum[num[i]+1])%mod;
ans=(ans+tmp+mod-1)%mod;
}
printf("%lld\n",ans);
return 0;
}
总结:学习了一下大数阶乘取模,还有求和奇数偶数处理,和康拓展开。平时还是要多做点题。