BC #40

2015-05-11 21:10:35

总结:迟到了N天的题解...

  状态比较浮躁... 只搞了一题+hack+2-1... 来说说题目吧。

 

A题 hdu 5224:暴力题

  水题... 只要从 1~sqrt(n) 枚举一下就可以了。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;

int T,n;

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        int a = (int)sqrt(1.0 * n);
        int b = 0;
        for(int i = a; i <= n; ++i){
            if(n % i == 0){
                a = i;
                b = n / i;
                break;
            }
        }
        printf("%d\n",a + a + b + b);
    }
    return 0;
}
View Code

 

B题 hdu 5225:数学题

  好题~!

  主要是考虑每一位的贡献... 

  对于第 k 位数 a[k],我们需要计算两部分答案,(1)a[k] 改变,(2)a[k] 不变。

  (1)找出 a[k+1] ~ a[n] 中比 a[k] 小的数的个数 cnt[k],如果在 cnt[k] 个数中随便

  选一个放到第 k 个位置,那么此时 k+1 ~ n 的位置的数就可以任意排列了(因为此时的字典序必定比原来小),假设

  我们要预处理出了 m 个数的所有排列里逆序数的总和 S[m],那么后面 n - k 个数所有排列的逆序数的和就是 S[n-k]。

  当然还要计算第 k 个位置和后面 n-k 个数产生的逆序数和,设后面 n-k 个数里面有 cnt 个数比当前第 k 个位置的数小,

  那么这部分答案就是 cnt * fac[n-k],(fac[i] 表示 i 的阶乘)。所以此时的答案是 S[n-k] + cnt * fac[n-k]。

  因为有 cnt[k] 个数可以被放到当前的位置,所以从最小的数开始逐个放到第 k 个位置,那么答案1:

  (2)如果 a[k] 不变,那么就要计算 cnt[k] * num[k+1],num[k+1] 表示第 k+1~n 个数的所有排列中比当前字典序

  小的排列数。这个 num[] 这个用康托的原理倒序计算。所以答案2就是上述的式子。

  (对于 S[] 数组的计算,可以这么考虑,现在有 n 个数,全部排列数:n!,考虑任意一对数,有 n!/2 的情况里会产生

  逆序数,所以 n 个数所有排列里总逆序数为:n!*C(n,2)/2 = n!*n*(n-1)/4

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const ll mod = 1e9 + 7;

int n;
int A[110];
ll ans,S[110],fac[110],num[110];
int cnt[110];

inline int Read(){
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}

int main(){
    S[1] = 0;
    S[2] = 1;
    S[3] = 9;
    S[4] = 72;
    fac[0] = 1;
    for(int i = 1; i <= 100; ++i)
        fac[i] = (fac[i-1] * i) % mod;
    for(int i = 5; i <= 100; ++i){
        S[i] = fac[i - 2] * (i*(i-1)/2) % mod * (i*(i-1)/2) % mod;
    }
    while(scanf("%d",&n) != EOF){
        memset(cnt,0,sizeof(cnt));
        memset(num,0,sizeof(num));
        for(int i = 1; i <= n; ++i)    A[i] = Read();
        for(int i = n; i >= 1; --i){
            for(int j = i + 1; j <= n; ++j)
                if(A[j] < A[i]) ++cnt[i];
            num[i] = num[i + 1] + (ll)cnt[i] * fac[n - i];
        }
        ans = 0;
        for(int i = 1; i <= n; ++i){
            int cnt = 0;
            for(int j = i + 1; j <= n; ++j) if(A[j] < A[i]) ++cnt;
            //printf("%d : cnt : %d , nun : %lld\n",i,cnt,num[i]);
            ans = (ans + num[i + 1] * (ll)cnt % mod 
                    + S[n - i] * (ll)cnt % mod) % mod;
            for(int j = 1; j < cnt; ++j){
                ans = (ans + (cnt - j) * fac[n - i] % mod) % mod;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

 

C题 hdu 5226:组合数学 + Luas 定理

  公式题... 要推得  

  那么剩下得就很好做了... 直接上Lucas。

  ※关键讲讲如何推得这个公式...

    首先我们需要一个众所周知的公式:

    考虑两项相加,根据上式,有如下过程:

    

   如果考虑三项,再加上 C(a+2,k),就有:,以此类推,就得到了顶上的公式!

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;

int X1,Y1,X2,Y2,p;
ll fac[100010],afac[100010];

ll Q_pow(ll x,ll y){
    ll res = 1;
    while(y){
        if(y & 1) res = res * x % p;
        x = x * x % p;
        y >>= 1;
    }
    return res;
}

ll C(int n,int m){
    return fac[n] * afac[n-m] % p * afac[m] % p;
}

ll Lucas(int a,int b){
    if(b > a) return 0;
    if(b == 0) return 1;
    return C(a % p,b % p) * Lucas(a / p,b / p) % p;
}

int main(){
    while(scanf("%d%d%d%d%d",&X1,&Y1,&X2,&Y2,&p) != EOF){
        fac[0] = afac[0] = 1;
        int top = max(X1,max(Y1,max(X2,Y2)));
        for(int i = 1; i <= top + 1; ++i){
            fac[i] = fac[i - 1] * (ll)i % p;
            afac[i] = Q_pow(fac[i],p - 2);
        }
        ll ans = 0;
        for(int i = Y1; i <= Y2; ++i){
            int a = max(X1,i);
            int b = max(X2 + 1,i);
            ans = (ans + (Lucas(b,i + 1) - Lucas(a,i + 1) + p) % p) % p;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2015-05-11 22:13  Naturain  阅读(91)  评论(0编辑  收藏  举报