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; }
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; }
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; }