CUG2012年暑期ACM训练赛(单人赛)
A题是一个模拟或者说是搜索吧
就跟倒可乐的问题差不多
原题是ZOJ1005题
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; char ans[101000][10]; int main(){ int tcase; scanf("%d", &tcase); //int flag = 0; while(tcase --){ int count = 0; int x, y, z; scanf("%d%d%d", &x, &y, &z); char a, b; if(x < y){ a = '1'; b = '2'; }else{ a = '2'; b = '1'; swap(x, y); } //int xx = 0, yy = 0; sprintf(ans[count++], "F(%c)\n", b); sprintf(ans[count++], "P(%c,%c)\n", b, a); int now = y - x; while(now != z){ // printf("%d %d %d %d\n", count, x , y,z ); if(now > x){ sprintf(ans[count++], "E(%c)\n", a); sprintf(ans[count++], "P(%c,%c)\n", b, a); now -= x; }else{ sprintf(ans[count++], "E(%c)\n", a); sprintf(ans[count++], "P(%c,%c)\n", b, a); sprintf(ans[count++], "F(%c)\n", b); sprintf(ans[count++], "P(%c,%c)\n", b, a); now = (now + y - x) % y; } if(count > 2500)break; } if(count > 2500){ puts("Impossible!"); }else{ printf("%d\n", count); for(int i = 0; i < count ; i ++) printf("%s", ans[i]);} if(tcase != 0) puts(""); } return 0; }
B题是一个凸包问题,我完全不会= =、
学弟们都会做。。。。我弱爆了啊
这题用的是ZY给我的模板,然后直接套的,最后加上一个圆的周长就行了
#include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; struct point{ double x, y; }p[1010], stack[1010]; int n, top; double mul(point a, point b, point c){ return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); } double dis(point a, point b){ return sqrt((a.x -b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); } int cmp(const void *a, const void *b){ point c = *(point *)a; point d = *(point *)b; double k = mul(p[0], c, d); if(k < 0 || (!k && dis(c, p[0]) > dis(d, p[0])) ) return 1; return -1; } void convex(){ for(int i = 1; i < n; i ++){ point tmp; if(p[i].y < p[0].y || (p[i].y == p[0].y && p[i].x < p[0].x)){ swap(p[i], p[0]); } } qsort(p + 1, n - 1, sizeof(p[0]), cmp); stack[0] = p[0]; stack[1] = p[1]; top = 1; for(int i = 2; i < n; i ++){ while(top >= 1 && mul(stack[top - 1], stack[top], p[i]) <= 0) top --; top ++; stack[top] = p[i]; } } int main(){ double r; while(~scanf("%d%lf", &n, &r)){ for(int i = 0; i < n; i ++){ scanf("%lf%lf", &p[i].x, &p[i].y); } convex(); double ans = 0; for(int i = 0; i < top ;i ++){ ans += dis(stack[i], stack[i+1]); } ans += dis(stack[top], stack[0]); ans += 2 * acos(-1.0) * r; printf("%.0f\n", ans); } return 0; }
C题就不说了,暴力能过,数据弱啊。。。。
#include<cstdio> int a[10000 + 10]; int main(){ int tcase; scanf("%d", &tcase); while(tcase --){ int n; scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%d", a + i); int flag = 0; for(int i = 2; i <= n - 1; i ++){ for(int j = 1; j < i; j ++){ for(int k = i + 1; k <= n; k ++){ if(a[j] + a[k] == 2 * a[i]){ flag = 1; break; } } if(flag) break; } if(flag) break; } if(flag) puts("Yes"); else puts("No"); } return 0; }
D题也不说了,不会做,搞不懂题,这么多人WA了,没有人过、。
E题纯数据结构+模拟啊,不想敲了,写起来太麻烦了
F题我开始用n^2的DP 直接 TLE了,后来ZY说用NlogN,然后就直接过了。。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct node{ int x, y; friend bool operator < (const node &a, const node &b){ return a.x < b.x; } }p[10010]; int dp[10010]; int a[10010]; int binary_search(int c[],int len,int v) { int left=0,right=len-1,mid=left+(right-left)/2; while(left<=right){ if(v>c[mid]) left=mid+1; else if(v<c[mid]) right=mid-1; else return mid; mid=left+(right-left)/2; } return left; } int main(){ int tcase; scanf("%d", &tcase); while(tcase --){ int n; scanf("%d", &n); for(int i = 0; i < n; i ++){ scanf("%d%d", &p[i].x, &p[i].y); dp[i] = 1; } sort(p, p + n); /* for(int i = 1; i < n; i ++){ for(int j = 0; j < i; j ++){ if(p[i].y> p[j].y) if(dp[i] < dp[j] + 1) dp[i] = dp[j] + 1; } } */ int top = 0; a[top++] = p[0].y; for(int i = 1; i < n; i ++){ if(a[top - 1] < p[i].y) a[top++] = p[i].y;else{ int tmp = binary_search(a, top, p[i].y); a[tmp] = p[i].y; } } int ans = 0; /* for(int i = 0; i < n; i ++) if(ans < dp[i]) ans = dp[i]; */ printf("%d\n", top); } return 0; }
G题不知道110是怎么出来的
H题还是有那么点意思的
我的思路是,对每一个点进行DFS
DFS的过程中,每走到一个C就把该点变成*
这样就能计数了
#include<cstdio> #include<cstring> int vis[10000 + 10]; char map[110][110]; int n,m; int dir[8][2]={ 1,1,1,0,1,-1,-1,1,-1,0,-1,-1,0,1,0,-1 }; void dfs(int x, int y){ map[x][y] = '*'; for(int i = 0; i < 8; i ++){ int xx = x + dir[i][0]; int yy = y + dir[i][1]; if(map[xx][yy] == 'C'){ dfs(xx, yy); } } } int main(){ scanf("%d%d", &n, &m); for(int i = 0; i < n; i ++) scanf("%s", map[i]); memset(vis, -1, sizeof(vis)); int count = 0; for(int i = 0; i < n; i ++){ for(int j = 0; j < m ; j ++) if(map[i][j] == 'C'){ dfs(i, j); count ++; } } printf("%d\n", count); return 0; }
I题用java做的
当时没有编译器
直接vim编写的,那当然错误一大堆
后来还是装了eclipse了
import java.math.BigInteger; import java.util.Scanner; public class Main{ public static void main(String args[]){ Scanner cin = new Scanner(System.in); int t; t = cin.nextInt(); while(t-- != 0){ int n; n = cin.nextInt(); n --; BigInteger a = cin.nextBigInteger(); while(n-- != 0){ BigInteger b = cin.nextBigInteger(); //System.out.println(b); //a.subtract(b); //System.out.println(a.subtract(b)); a = a.subtract(b); } System.out.println(a); } } }
J题不会做
做了6题,感觉最遗憾的当是图论那题和最后一题了,不会啊。。继续加油学吧
--------------------------------更新----------------------------------------------
本来不想做的,数论不会啊。。。。但怕第一的位子没了。。还是做了
不过做是做了,也是看着解题报告做的= =原题
http://poj.org/problem?id=2154 就是这题了,一看出处吓死了,楼教主的原题啊。。
一开始的时候以为是polya定理来做,然后就直接套模板敲了
不过后来发现不一样啊,并不翻转
然后就找特殊情况加着求了,然后果断TLE
10亿的数据啊。。。
后来问了dream神,他给我讲了一通
然后他告诉我是哪题了,再去看解题报告 。。。
很遗憾。。。没有完全看懂。。。大概的理解了。。
解法也在下面了。。
#include<iostream> #include<math.h> #include<cstdio> #include<cstring> using namespace std; /* 置换只有旋转一种方式,那么共有n个置换 基本知识:环的个数为gcd(n , i) , 长度L=n / gcd(n , i) 其中 i 为转的位子数 普通求法: ∑n^( gcd(n,i) ) 0<=i<n 复杂度过高 优化:枚举环的长度L 枚举优化: L可以从1取到sqrt(n) ,因为L|n , n/L | n 对于每个L,我们再看有几个i满足条件 n/L = gcd(n , i) 那么令 a=n/L = gcd(n , i) , 再设i = at 那么当且仅当gcd(L,t)=1时候,才有gcd(n,i) = a 显然满足条件的i的个数就是t的个数也就是phi(L) 那么最后统计一下就是 ∑(phi(L) * N^(L-1) ) % p (L即枚举值) */ const int maxn = 50000; bool IsNotPrime[maxn]; // 判断是否为素数. int PrimeList[maxn]; // 素数列表. int PrimeNum; void Prime_Linear(void) { // 速度比朴素筛法快2倍以上,该筛法进行稍微修改即可用于求欧拉函数Phi[]. int i, j; memset(IsNotPrime, 0, sizeof(IsNotPrime)); // 初始赋值所有数都是素数. IsNotPrime[1] = 1; IsNotPrime[0] = 1; // 0和1不是素数. PrimeList[0]=2; for (i = 4; i < maxn; i += 2) IsNotPrime[i] = 1; // 除2以外的所有偶数都不是素数. PrimeNum = 1; for (i = 3; i < maxn; i += 2) { if (!IsNotPrime[i]) { // 如果是素数则加入素数列表. PrimeList[PrimeNum++] = i; } // 注意:这里与朴素筛法不同,即使合数也要进行筛. // 因为这里素数只筛它的素数倍,那么有些合数就可能没被筛掉. // 而这些合数就需要合数来晒,而且只要筛到它的最小质因子倍即可(想想为什么?). for (j = 0; j < PrimeNum && i * PrimeList[j] < maxn; j++) { IsNotPrime[i * PrimeList[j]] = 1; if (i % PrimeList[j] == 0) { // 说明PrimeList[j]是i的最小质因子,即i * PrimeList[j]的最小质因子,则跳出. break; } } } } int modular_exponent(int a, int b, int n){ int ret = 1; a %= n; for( ; b; b >>= 1, a = (int)( (long long )a) * a % n ){ if(b & 1) ret = (int)((long long )ret) * a % n; } return ret; } int euler(int x){ int res = x; for(int i = 0; i < PrimeNum && PrimeList[i] * PrimeList[i] <= x; i ++){ if(x % PrimeList[i] == 0){ res = res / PrimeList[i] * (PrimeList[i] -1); while(x % PrimeList[i] == 0){ x /= PrimeList[i]; } } } if(x > 1) res = res / x * ( x - 1); return res; } int main(){ int tcase; scanf("%d", &tcase); Prime_Linear(); while(tcase --){ int n, p; scanf("%d%d", &n, &p); int ans = 0; int i; for( i = 1; i * i < n; i ++) if(n%i == 0){ ans = (ans + euler(i) % p * modular_exponent(n, n/i-1, p) + euler(n/i) %p * modular_exponent(n, i-1, p)) % p; } if (i * i == n) ans = (ans + euler(i) * modular_exponent(n, i-1, p)) % p; printf("%d\n", ans); } return 0; }
D题继续不懂,他说我没有看清题 ?听说是CF的原题。。。
E题继续打死不写
G题是网络流啊,110也知道是怎么出来的了
因为题目中已经说清楚了是无向边
不过数据中竟然给了2 3 和3 2 这种情况。。。。。这。。。。太坑了啊。。
因为边可能重边之类的
所以要用floyd来计算最短路了,即所有点之间的最短值了。。。
然后就是用网络流了。。。
不会啊,还不理解。。。
还是巩固下吧
-----------------------继续更新--------------------------
C题,原来没看清题啊。。跪
出现的数一定是从1-n并且全部填完的。。。这样的话,就跟逆序数那题差不多啊。。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int a[10000+10]; int flag[10000+10]; int main(){ int tcase; scanf("%d", &tcase); while(tcase --){ int n; memset(flag, 0, sizeof flag); scanf("%d", &n); for(int i = 0; i < n; i ++) scanf("%d", a + i); int f = 0; /* for(int i = 0; i < n; i ++){ flag[ a[i] ] = 1; for(int j = a[i] + 1; j < n -a[i]; j ++){ if(flag[ a[i] - j] + flag[ a[i] + j] == 1){ f = 1; break; } } if(f) break; } */ //JZ同学说只要大于5一定是YES了Orz if(n >= 5){ puts("Yes"); continue; } for(int i = 0; i < n; i ++){ for(int j = 0; j < i; j ++){ for(int k = i + 1; k < n; k ++){ if(a[i] * 2 == a[j] + a[k]){ f = 1; break; } } } } if(f) puts("Yes"); else puts("No"); } return 0; }
D题,单调队列
见这个
http://www.cnblogs.com/louzhang/archive/2012/08/01/2617837.html
这个就更新到这吧,博客也写的挫。。。写的也累死了
posted on 2012-07-28 23:26 louzhang_swk 阅读(392) 评论(0) 编辑 收藏 举报