中大网络赛1000 C(n,m) again

第一次过的代码,0.55sec,用了化成对数的方法+大数。

// source code of submission 701149, Zhongshan University Online Judge System #include<stdio.h> #include<string.h> #include<algorithm> #include<cmath> #include<iostream> using namespace std; typedef unsigned long long ll; ll m, n; #include<iostream> using namespace std; const int maxlen = 10010; class HP { public: friend ostream &operator<<(ostream &cout, const HP &x); friend bool operator<(const HP &a, const HP &b); int len, s[maxlen]; HP() { (*this) = (ll)0; } HP(int inte) { (*this) = inte; } HP(const char *str) { (*this) = str; } HP operator=(ll inte); HP operator=(const char *str); HP operator*(const HP &b); HP operator+(const HP &b); HP operator-(const HP &b); HP operator/(const HP &b); HP operator%(const HP &b); int Compare(const HP &b) const; }; ostream &operator<<(ostream &cout, const HP &x) { for(int i = x.len; i >= 1; i--) cout << x.s[i]; return cout; } HP HP::operator =(const char *str) { len = strlen(str); for(int i = 1; i <= len; i++) s[i] = str[len-i] - '0'; return *this; } HP HP::operator =(ll inte) { if(inte == 0) { len = 1; s[len] = 0; } for(len = 0; inte > 0;) { s[++len] = inte%10; inte /= 10; } return (*this); } HP HP::operator *(const HP &b) { ll i, j; HP c; c.len = b.len + len; for(i = 1; i <= c.len; i++) c.s[i] = 0; for(i = 1; i <= len; i++) for(j = 1; j <= b.len; j++) c.s[i+j-1] += s[i]*b.s[j]; for(i = 1; i < c.len; i++) { c.s[i+1] += c.s[i]/10; c.s[i] %= 10; } while(c.s[i]) { c.s[i+1] = c.s[i]/10; c.s[i] %= 10; i++; } while(i > 1 && !c.s[i]) i--; c.len = i; return c; } HP HP::operator +(const HP &b) { int i; HP c; c.s[1] = 0; for(i = 1; i <= len || i <= b.len || c.s[i]; i++) { if(i <= len) c.s[i] += s[i]; if(i <= b.len) c.s[i] += b.s[i]; c.s[i+1] = c.s[i] / 10; c.s[i] = c.s[i] % 10; } c.len = i-1; if(c.len == 0) c.len = 1; return c; } HP HP::operator -(const HP &b) { int i, j; HP c; for(i = 1, j = 0; i <= len; i++) { c.s[i] = s[i] - j; if(i <= b.len) c.s[i] -= b.s[i]; if(c.s[i] < 0) { j = 1; c.s[i] += 10; } else j = 0; } c.len = len; while(c.len > 1 && !c.s[c.len]) c.len--; return c; } bool operator <(const HP &a, const HP &b) { if(a.Compare(b) < 0) return true; return false; } int HP::Compare(const HP &b) const { if(len > b.len) return 1; if(len < b.len) return -1; int i = len; while((i > 1) && (s[i] == b.s[i])) i--; return s[i] - b.s[i]; } HP HP::operator /(const HP &b) { int i, j; HP d(0), c; for(i = len; i > 0; i--) { if(!(d.len == 1 && d.s[1] == 0)) { for(j = d.len; j > 0; j--) d.s[j+1] = d.s[j]; ++d.len; } d.s[1] = s[i]; c.s[i] = 0; while((j = d.Compare(b)) >= 0) { d = d-b; c.s[i]++; if(j == 0) break; } } c.len = len; while((c.len > 1) && (c.s[c.len] == 0)) c.len--; return c; } HP HP::operator %(const HP &b) { int i, j; HP d(0); for(i = len; i > 0; i--) { if(!(d.len == 1 && d.s[1] == 0)) { for(j = d.len; j > 0; j--) d.s[j+1] = d.s[j]; ++d.len; } d.s[1] = s[i]; while((j = d.Compare(b)) >= 0) { d = d-b; if(j == 0) break; } } return d; } ll cal(ll n, ll m) { ll ans; if(m == 0 || (n == m)) return 1; if(m < n / 2.0) m = n - m; ll i = 1; double s1 = 0; for(i = m + 1; i <= n; i++) s1 += log(double(i)); double s2 = 0; for(i = 2; i <= n - m; i++) s2 += log(double(i)); ans = ceill(exp(s1 - s2)); return ans; } void c(ll n,ll m) { HP mm; mm= 1; m = min(m, n - m); HP nh; nh =n; HP mh; mh=m; for(int i = 0; i < m; i++) { mm = mm * nh; nh= nh -1; } for(int i = m; i >= 1; i--) mm = mm / i; cout << mm << endl; } int main() { int t; scanf("%d", &t); while(t--) { cin >> n >> m; if(m <= 1000 || (n - m) <= 1000) c(n, m); else cout << cal(n, m) << endl; } return 0; } 

后来比赛完了,我队友说这题不用用大数去做,直接unsigned long long 的乘除法就可以,今天有空就想了一下,妈的,真的可以,0.0sec..技巧挺强的,前一段的连续一个序列跟后一段连续的一个序列肯定能够整除的,不过要前一段连续序列要从1开始,这样保证了可以整除,题目的保证了不会溢出,那直接。。。。。。。。。。。。。。蛋疼啊

#include <iostream> using namespace std; typedef unsigned long long ULL; ULL n, m; ULL gcd(ULL a, ULL b) { return b == 0 ? a : gcd(b, a % b); } //#define TEST int main() { #ifdef TEST freopen("input.txt", "r", stdin); #endif int t; cin >> t; while(t--) { cin >> n >> m; if(m > n - m) m = n - m; ULL tmpi = 1; ULL tmpn = 1; ULL ans = 1; for(ULL i = 1; i <= m; i++) { tmpi = i; tmpn = n - i + 1; ULL g = gcd(tmpn, tmpi); tmpn /= g; tmpi /= g; g = gcd(ans, tmpi); ans /= g; tmpi /= g; ans = ans * tmpn / tmpi; } cout << ans << endl; } return 0; } 

你可能感兴趣的:(中大网络赛1000 C(n,m) again)