codeforces #297 div2(only)
2015-03-28 01:34:38
总结:这场用来练java了...
赛中搞了A,B,C,然后开始坑E题... 暴力DFS结果TLE了... rank 300+(unofficial)
赛后用c++补了D、E...(因为发现java的JSTL有点烦...)
A:模拟题,从左到右扫一遍,维护一个计数数组即可。
1 import java.util.Scanner; 2 3 public class Main{ 4 public static void main(String[] args){ 5 Scanner in = new Scanner(System.in); 6 int n = in.nextInt(); 7 String str = in.next(); 8 char[] s = new char[str.length()]; 9 s = str.toCharArray(); 10 int[] cnt = new int[30]; 11 int sum = 0; 12 for(int i = 0; i < str.length(); ++i){ 13 if(s[i] >= 'a' && s[i] <= 'z'){ 14 cnt[(int)(s[i] - 'a')]++; 15 } 16 else{ 17 int id = (int)(s[i] - 'A'); 18 if(cnt[id] == 0) sum++; 19 else cnt[id]--; 20 } 21 } 22 System.out.println(sum); 23 in.close(); 24 } 25 26 }
B:经典的区间翻转,首先开一个cnt[]数组来计数,对于每一个操作[l,r],我们给cnt[l]++,最后才从1~n扫一遍,不断累加cnt[]
如果累加值为奇数那么该数与对称位置的数交换,否则不交换。
1 import java.util.Scanner; 2 3 public class Main{ 4 public static void main(String[] args){ 5 Scanner in = new Scanner(System.in); 6 char[] s = new char[200010]; 7 String str = in.next(); 8 s = str.toCharArray(); 9 int a,m = in.nextInt(); 10 int[] v = new int[100010]; 11 for(int i = 0; i < m; ++i){ 12 a = in.nextInt(); 13 v[a - 1] += 1; 14 } 15 int cur = 0; 16 for(int i = 0; i < str.length() / 2; ++i){ 17 cur += v[i]; 18 if(cur % 2 == 1){ 19 char tmp = s[i]; 20 s[i] = s[str.length() - 1 - i]; 21 s[str.length() - 1 - i] = tmp; 22 } 23 } 24 System.out.println(s); 25 in.close(); 26 } 27 28 }
C:排序之后从最大的stick开始贪心扫描即可。
1 import java.util.*; 2 3 public class Main{ 4 public static void main(String[] args){ 5 Scanner in = new Scanner(System.in); 6 int n = in.nextInt(); 7 int[] l = new int[n]; 8 for(int i = 0; i < n; ++i) l[i] = in.nextInt(); 9 Arrays.sort(l); 10 int[] v = new int[2]; 11 int sz = 0; 12 long ans = 0; 13 for(int i = n - 1; i >= 1; --i){ 14 if(l[i]==l[i-1]){ 15 v[sz++] = l[i]; 16 --i; 17 } 18 else if(l[i]==l[i-1]+1){ 19 v[sz++] = l[i - 1]; 20 --i; 21 } 22 if(sz >= 2){ 23 ans += (long)v[0] * (long)v[1]; 24 sz = 0; 25 } 26 } 27 System.out.println(ans); 28 in.close(); 29 } 30 31 }
D:神奇的规律... 只要一个2*2的矩阵里面有3个“.”,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=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 #define X first 21 #define Y second 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 int n,m; 28 char g[2010][2010]; 29 queue<pii > Q; 30 bool inq[2010][2010]; 31 int dir[4][3][2] = {{{-1,-1},{-1,0},{0,-1}},{{-1,0},{-1,1},{0,1}}, 32 {{0,-1},{1,-1},{1,0}},{{0,1},{1,0},{1,1}}}; 33 34 int main(){ 35 scanf("%d%d",&n,&m); 36 REP(i,n) scanf("%s",g[i]); 37 REP(i,n) REP(j,m) if(g[i][j] == '*'){ 38 Q.push(MP(i,j)); 39 inq[i][j] = 1; 40 } 41 while(!Q.empty()){ 42 pii cur = Q.front(); Q.pop(); 43 inq[cur.X][cur.Y] = 0; 44 bool flag = false; 45 REP(o,4){ 46 int cnt = 0; 47 REP(k,3){ 48 int tx = cur.X + dir[o][k][0]; 49 int ty = cur.Y + dir[o][k][1]; 50 if(tx < 0 || tx >= n || ty < 0 || ty >= m 51 || g[tx][ty] == '*') break; 52 cnt++; 53 } 54 if(cnt == 3){ 55 flag = true; 56 break; 57 } 58 } 59 if(flag){ 60 g[cur.X][cur.Y] = '.'; 61 REP(o,4) REP(k,3){ 62 int tx = cur.X + dir[o][k][0]; 63 int ty = cur.Y + dir[o][k][1]; 64 if(tx < 0 || tx >= n || ty < 0 || ty >= m || g[tx][ty] == '.') 65 continue; 66 if(inq[tx][ty] == 0){ 67 inq[tx][ty] = 1; 68 Q.push(MP(tx,ty)); 69 } 70 } 71 } 72 } 73 REP(i,n){ 74 REP(j,m) printf("%c",g[i][j]); 75 puts(""); 76 } 77 return 0; 78 }
E:一开始暴力... 果断T了。后来才知道是折半枚举,其实也明显,n<=25,直接枚举是3^25,如果折半就是3^12 , 3^13。
所以我们将n分成两部分,分别暴力DFS搜索,用两个map数组来记录两部分得到的“和”,及其数量。
(比如mp1[i][j]表示前半部分,有i个cube被贴上“!”标签得到的和为j的数量)
分别搜素得到两个map数组后,我们可以枚举前半部分贴了i = 0~k个“!”标签,再枚举后半部分贴了0 <= j <= i 个“!”标签:
那么问题就变成遍历mp1[i]的所有元素element,在mp2[j]中找S - element。
所以,在过程中累加答案即可。
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=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 25 int n,k,top; 26 ll S,a[30],af[30]; 27 map<ll,int> mp1[30],mp2[30]; 28 29 void Dfs1(int p,int num,ll sum){ 30 if(p >= top){ 31 mp1[num][sum]++; 32 return; 33 } 34 Dfs1(p + 1,num,sum); 35 if(sum + a[p] <= S) Dfs1(p + 1,num,sum + a[p]); 36 if(a[p] <= 18 && num < k && sum + af[p] <= S) 37 Dfs1(p + 1,num + 1,sum + af[p]); 38 } 39 40 void Dfs2(int p,int num,ll sum){ 41 if(p >= n){ 42 mp2[num][sum]++; 43 return; 44 } 45 Dfs2(p + 1,num,sum); 46 if(sum + a[p] <= S) Dfs2(p + 1,num,sum + a[p]); 47 if(a[p] <= 18 && num < k && sum + af[p] <= S) 48 Dfs2(p + 1,num + 1,sum + af[p]); 49 } 50 51 int main(){ 52 scanf("%d%d%I64d",&n,&k,&S); 53 REP(i,n){ 54 scanf("%I64d",&a[i]); 55 if(a[i] <= 18){ 56 af[i] = 1; 57 for(int j = 2; j <= a[i]; ++j) af[i] *= (ll)j; 58 } 59 } 60 top = n / 2; 61 Dfs1(0,0,0); 62 Dfs2(top,0,0); 63 map<ll,int>::iterator it1,it2; 64 ll ans = 0; 65 for(int i = 0; i <= k; ++i){ 66 for(it1 = mp1[i].begin(); it1 != mp1[i].end(); it1++){ 67 for(int j = 0; j <= k - i; ++j) 68 ans += (*it1).second * mp2[j][S - (*it1).first]; 69 } 70 } 71 printf("%I64d\n",ans); 72 return 0; 73 }