逆序对
题目描述
求所有长度为n的01串中满足如下条件的二元组个数:
设第i位和第j位分别位ai和aj(i<j),则ai=1,aj=0。
答案对1e9+7取模。
n <= 1e18
一般的逆序对都可以用归并排序、树状数组(O(nlogn))等,但显然此题是一个公式题。
首先公式里应该有与2^n有关的项,长度为n的串总共有2 ^ n个;
n = 1, ans = 0;
n = 2, ans = 1;
n = 3, ans = 6;
n = 4 ,ans = 24; //此时我们便可以猜了;ans = 2 ^(n−3) ∗n∗(n−1);
正解:首先我们任选两个位置构造一对逆序对 10,那么剩下的位置能组合出的串的数量( 2^(n-2) )就是这对逆序对的总计数次数,所以总的数量就是 ans = C(n,2) * 2^(n-2) 与上边相符;
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL quick(LL a,LL b){
LL ans=1;
while(b){
if(b&1) ans = ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
int main()
{
LL n;
cin>>n;
if(n<2){
cout<<0<<endl;
return 0;
}
LL ans = quick(2,n-2)%mod;
LL inv = quick(2,mod-2)%mod;
ans = ((n%mod)*((n-1)%mod))%mod*inv%mod*ans%mod; //注意先对n取模
cout<<ans<<endl;
return 0;
}
Treepath
直接按深度的奇偶组合一下就可以了;
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+7;
int h[N],e[N*2],ne[N*2],idx;
int dep[N];
void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int s,int f)
{
dep[s] = dep[f] + 1;
for(int i=h[s];~i;i=ne[i]){
int j = e[i];
if(j==f) continue;
dfs(j,s);
}
}
int main()
{
int n;
cin>>n;
memset(h,-1,sizeof h);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dep[0]=-1;
dfs(1,0);
LL ans = 0,odd=0,even=0;
for(int i=1;i<=n;i++) if(dep[i]&1) odd++;
even = n-odd;
ans = odd*(odd-1)/2 + even*(even-1)/2;
cout<<ans<<endl;
return 0;
}