Bestcoder #32
2015-03-08 19:03:57
思路:这场打得不好... 怒降滚粗...
T1紧张+粗心傻逼地 wa 了两发...
T2知道怎么做... 但是wa到死 TAT,最后拿自己的错误点hack了一发,骗了点分...
T3、T4没看。
赛后补了T2、T3、T4。
T3,公式证明半天... 一个细节没考虑... wa好多发QAQ
T4,一道挖掘隐藏条件的DP... 很水... 竟然放在最后,坑死了。
T1:三关键词排序...
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=1;i<=(n);++i) 17 #define REV(i,n) for(int i=(n);i>=1;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 int n; 28 struct node{ 29 int a,b,id; 30 }nd[105]; 31 32 bool cmp(node a,node b){ 33 if(a.a - a.b == b.a - b.b){ 34 if(a.b == b.b) return a.id < b.id; 35 return a.b < b.b; 36 } 37 return (a.a - a.b) > (b.a - b.b); 38 } 39 40 int main(){ 41 while(scanf("%d",&n) != EOF){ 42 REP(i,n) scanf("%d%d",&nd[i].a,&nd[i].b),nd[i].id = i; 43 sort(nd + 1,nd + n + 1,cmp); 44 REP(i,n){ 45 printf("%d%c",nd[i].id - 1,i == n ? '\n' : ' '); 46 } 47 } 48 return 0; 49 }
T2:维护前缀和,然后用set查找... 注意限时卡的很死... 尽量少开set和变量... set的操作也尽量少。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <set> 6 #include <iostream> 7 #include <algorithm> 8 using namespace std; 9 10 int T,n,K; 11 long long sum[1000010]; 12 set<long long> st; 13 int A[1000010]; 14 15 inline int Read(){ 16 int x = 0,f = 1;char ch = getchar(); 17 while(ch < '0' || ch > '9'){if(ch == '-')f = -1;ch = getchar();} 18 while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} 19 return x * f; 20 } 21 22 int main(){ 23 T = Read(); 24 for(int tt = 1; tt <= T; ++tt){ 25 st.clear(); 26 n = Read(); 27 K = Read(); 28 for(int i = 1; i <= n; ++i) A[i] = Read(); 29 bool flag = false; 30 for(int i = 1; i <= n; ++i){ 31 if(i & 1) sum[i] = sum[i - 1] + A[i]; 32 else sum[i] = sum[i - 1] - A[i]; 33 } 34 for(int i = n; i >= 1; --i){ 35 st.insert(sum[i]); 36 long long cur = (i & 1) ? sum[i - 1] + K : sum[i - 1] - K; 37 if(st.count(cur)){ 38 flag = true; 39 break; 40 } 41 } 42 if(flag) printf("Case #%d: Yes.\n",tt); 43 else printf("Case #%d: No.\n",tt); 44 } 45 return 0; 46 }
T3:一个组合数学题... 将左括号、右括号看做向右走、向上走,然后就是一个从(0,0)走到(n/2,n/2)且不跨越y=x的问题,因为已经给出了部分前缀,
所以等于从(x,y)到(n/2,n/2),再转化为从(0,0)走到(a,b)且不跨越y=x。这个种类数是C(a+b,b) - C(a+b,b-1)。
简证:把问题“从(0,0)走到(a,b)且不跨越y=x的种数”,转化为“从(0,-1)走到(a,b-1)且不接触y=x的种数”。
那么如何解决这个问题呢,我们先算出所有情况(C(a+b,b)),再减去有接触y=x的情况。
※设接触点为(k,k),我们发现(0,-1)->(k,k)的路径条数等于(-1,0)->(k,k)的路径条数。(即使接触点再多,我们都可以对称一下,转化到起点为(-1,0))
那么从(0,-1)->(a,b-1)有接触y=x的情况总数为(-1,0)到(a,b-1)的路径数,为C(a+b,b-1)。
综上,从(0,0)->(a,b)且不跨越y=x的种数为C(a+b,b) - C(a+b,b-1),证毕。
注意:需要预先判断给出的前缀是否合法... 每时每刻都要判断左括号数是否 >= 右括号数。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=1;i<=(n);++i) 17 #define REV(i,n) for(int i=(n);i>=1;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 const ll mod = 1000000007LL; 27 const int MAXN = 1000000; 28 29 int N; 30 ll fac[MAXN + 10],afac[MAXN + 10]; 31 char s[MAXN + 10]; 32 33 ll Q_pow(ll x,ll y){ 34 ll res = 1,X = x; 35 while(y){ 36 if(y & 1) res = res * X % mod; 37 X = X * X % mod; 38 y >>= 1; 39 } 40 return res; 41 } 42 43 void Pre(){ 44 fac[0] = 1; 45 REP(i,MAXN) fac[i] = fac[i - 1] * (ll)i % mod; 46 afac[MAXN] = Q_pow(fac[MAXN],mod - 2); 47 RFOR(i,MAXN - 1,0) afac[i] = afac[i + 1] * (i + 1) % mod; 48 } 49 50 ll Comb(ll n,ll m){ 51 if(n < m || m < 0) return 0; 52 return fac[n] * afac[m] % mod * afac[n - m] % mod; 53 } 54 55 bool Judge(int &q,int &p){ 56 if(N & 1) return false; 57 q = p = N / 2; 58 int len = strlen(s); 59 for(int i = 0; i < len; ++i){ 60 if(s[i] == '(') q--; 61 else p--; 62 if(q > p) return false; 63 } 64 if(q < 0 || p < 0) return false; 65 return true; 66 } 67 68 int main(){ 69 Pre(); 70 while(scanf("%d",&N) != EOF){ 71 scanf("%s",s); 72 int q,p; 73 if(!Judge(q,p)){ 74 printf("0\n"); 75 continue; 76 } 77 ll ans = (Comb(p + q,q) - Comb(p + q,q - 1) + mod) % mod; 78 printf("%d\n",(int)ans); 79 } 80 return 0; 81 }
T4:DP,和以前一道cf题有点像,需要挖掘出“某些变量的变化范围不大”这个隐藏条件。
因为x1~xn非严格递增,所以最大的xn不会超过sqrt(2×n),那么就可以枚举了,复杂度为n×sqrt(n)
dp[i][j]表示用前i个数(0~i),组成和为j的情况数。dp[i][j] = dp[i][j - i] + dp[i - 1][j - i]。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=1;i<=(n);++i) 17 #define REV(i,n) for(int i=(n);i>=1;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 int T,n,m; 28 int dp[320][50010]; 29 30 int main(){ 31 scanf("%d",&T); 32 REP(tt,T){ 33 scanf("%d%d",&n,&m); 34 int top = sqrt(2.0 * n); 35 dp[0][0] = 1; 36 REP(i,top){ 37 int up = min(n,i * n); 38 for(int j = i * (i + 1) / 2; j <= up; ++j){ 39 dp[i][j] = (dp[i][j - i] + dp[i - 1][j - i]) % m; 40 //printf("dp[%d][%d] : %d\n",i,j,dp[i][j]); 41 } 42 } 43 int ans = 0; 44 REP(i,top) ans = (ans + dp[i][n]) % m; 45 printf("Case #%d: %d\n",tt,ans); 46 } 47 return 0; 48 }