6.4考试T1听课笔记
T1:
长度为n,共有n!个全排列
暴力做法:计算每个全排列的逆序对数量,再快速幂计算每个全排列的贡献,求和取模,得结果
借此来复习一下逆序对和快速幂的写法吧~
逆序对:这是常规做法,当然我们也可以考虑用线段树来实现 只要不嫌麻烦(参考题:luoguP3608)
void cmp(ll l,ll r){ if(l == r){ return; } int mid = (l + r) >> 1; cmp(l,mid); cmp(mid + 1,r); int i = l,j = mid + 1 ,k = l; while(i <= mid && j <= r){ if(a[i] <= a[j]) b[k] = a[i],k++,i++; else b[k] = a[j],k++,j++,ans += mid - i + 1; } while(i <= mid){ b[k] = a[i],k++,i++; } while(j <= r){ b[k] = a[j],k++,j++; } for(int i=l;i<=r;i++){ a[i] = b[i]; } }
快速幂:
int ksm(int a,int b,int mod){ int ans=1; while(b){ if(b&1) ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans%mod; }
正解:
根据上上考试题目全和逆序对有关但一个逆序对的做法都没有用的经验来看,我们可以将此n个排列看作在之前的排列中插入一个数,去计算插入数的贡献。
由于题目中的公式并不好搞,所有我们将它拆成两个子问题来解决
代码:
#include<iostream> #include<cstdio> #define int long long using namespace std; const int mod = 1e9 + 7; const int Z = 1e6 + 50; int n,k,T; int vis[Z],a[Z],cnt[Z]; int read() { int x=0,w=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') w=-1; c=getchar(); } while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x*w; } signed main(){ //freopen("concert.in","r",stdin); //freopen("concert.out","w",stdout); T = read(); while(T-- > 0){ int ans1 = 1,sum1= 1,g = 1; int ans2 = 0,ans3 = 0,sum2 = 0,sum3 = 0,jc = 1; n = read(),k = read(); for(int i=1;i<n;i++){ g = g * k % mod; sum1 = (sum1 + g) % mod; ans1 = ans1 * sum1 % mod; } for(int i=1;i<n;i++){ jc = jc * i % mod; sum2 = (sum2 + 2 * i) % mod; sum3 = (sum3 + i * i % mod) % mod; ans2 = ((i + 1) * ans2 % mod + ans3 * sum2 % mod + sum3 * jc % mod) % mod; ans3 = ((i + 1) * ans3 % mod + ((i + 1) * i / 2) % mod * jc % mod) % mod; } printf("%lld\n",(ans1 + ans2) % mod); } return 0; }
另附:

浙公网安备 33010602011771号