2013-5-17 训练赛总结
训练赛链接: http://openoj.awaysoft.com:8080/judge/contest/view.action?cid=424#overview
题目来源: The 10th Zhejiang Provincial Collegiate Programming Contest
还是想吐嘈 ZOJ的题目描述,与模拟题的恶心程度........
A Applications
背景是ACM集训队选拔,根据OJ题数,区域赛获奖,CF/TC排名, 还有个性别, 注意的地方是CF不满三场不计算.
#include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<string> #include<map> #include<algorithm> using namespace std; const int N = 1010; bool isprime(int x){ for(int i = 2; i*i <= x; i++) if( x%i == 0 ) return false; return true; } int n, m; bool cmp(int a,int b){ return a > b; } map< string, int > regional; map< int, double > tiku; const double esp = 1e-8; int sign(double x){ return x < -esp ? -1 : (x >esp); } struct Peason{ string name; string team_name; string sex; double score; vector<int> problem; vector<int> cf; void read(){ // init problem.clear(); cf.clear(); char tmp[50]; int oj_num, cf_num, x; scanf("%s",tmp); name = tmp; scanf("%s",tmp); team_name = tmp; scanf("%s",tmp); sex = tmp; scanf("%d %d",&oj_num,&cf_num ); for(int i = 0; i < oj_num; i++){ scanf("%d", &x); problem.push_back(x); } for(int i = 0; i < cf_num; i++){ scanf("%d", &x); cf.push_back(x); } } void modify(){ score = 0; if( regional.count( team_name ) ){ int d = regional[team_name]; if( d == 1 ) score += 36; else if( d == 2 ) score += 27; else if( d == 3 ) score += 18; } for(int i = 0; i < (int)problem.size(); i++){ int d = problem[i]; if( tiku.count(d) != 0 ) score += tiku[d]; else if( isprime(d) ) score += 1; else score += 0.3; } if( cf.size() >= 3 ){ sort( cf.begin(), cf.end(), cmp ); int r = cf[2]; score += max( 0.0, (r-1200)/100. )*1.5; } if( sex == "F" ) score += 33; } bool operator < (const Peason &tmp) const{ if( sign(score-tmp.score) != 0 ){ return sign(score-tmp.score) == 1; } else return name < tmp.name; } }p[N]; void gao(){ scanf("%d%d", &n, &m); // tiku info int pro_n, x; scanf("%d", &pro_n); tiku.clear(); for(int i = 0; i < pro_n; i++){ scanf("%d", &x); tiku[x] = 2.5; } scanf("%d", &pro_n); for(int i = 0; i < pro_n; i++){ scanf("%d", &x); tiku[x] = 1.5; } // regional int team_num, rank; char str[N]; scanf("%d", &team_num ); regional.clear(); for(int i = 0; i < team_num; i++){ scanf("%s %d", str, &rank ); regional[str] = rank; } //peason for(int i = 0; i < n; i++) p[i].read(), p[i].modify(); sort( p, p+n ); for(int i = 0; i < m; i++) printf("%s %.3lf\n", p[i].name.c_str(), p[i].score ); } int main(){ int T; scanf("%d", &T); while( T-- ){ gao(); } return 0; }
B Break Standard Weight
已知a,b,枚举c, 取值范围 [1,a/2 ], 然后枚举天平左右放置情况, 再做一次(b,a)就好.
#include<cstdio> #include<cstring> #include<cstdlib> #include<set> #include<map> #include<cmath> #include<algorithm> using namespace std; const int N = 500; bool vis[N]; int w[3]; int cao(int a,int b,int c){ memset(w,0,sizeof(w)); memset(vis,0,sizeof(vis)); vis[0] = 1; int cnt = 0; for(int i = 0; i <= 2; i++) { w[i] += a; for(int j = 0; j <= 2; j++) { w[j] += b; for(int k = 0; k <= 2; k++) { w[k] += c; int t = abs( w[1]-w[2] ); if( !vis[t] ) vis[t] = 1, cnt += 1; w[k] -= c; } w[j] -= b; } w[i] -= a; } return cnt; } int gao(int a,int b){ int res = 0; for(int c = 1; c <= a/2; c++){ // a, b, c res = max( res, cao( a-c, c, b ) ); } return res; } int main(){ int T; scanf("%d", &T); while( T-- ){ int x, y; scanf("%d%d", &x,&y); printf("%d\n", max( gao(x,y), gao(y,x) ) ); } return 0; }
C Calculate Prime S
首先通过枚举子集数量k, 得到Sn计算式子, Sn = \sum C( n-k+1, k ), 然后可看出来(输出前面一部分)是fibonacci数.
而对于 S 是prime的定义, 其实就是 Fibonacci素数, 对于fibonacci素数,这里可以得出两个性质:
1. 从第5项(前五项为:1,1,2,3,5) 开始, 项数为素数,则Fi为Fib素数. 可通过 假定Fi%M, 然后由 Fk = 0, 则 F_(t*k) = 0, 得出.
2. Fibonacci数 Fi % M, 必有循环节, 且循环节长度是 O(M), 不太会证明. -_-..据说要部分代数.
然后解题思路是, 求出第k个S prime, 其实就是 第k个素数(前两项2,3,应该替换成3,4), 然后 Sn从P_k开始枚举, 当出现 Sn%x = 0, 则找到了对应的Sn.但是最终结果所求为 (Sn/x)%M, 可以转换成 Sn%(x*M). 然后最后再除以一个 X即可. 求 Fibonacci数 通过构造转置矩阵,快速幂求即可.
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; typedef long long LL; const int N = (int)2e7+10; int prime[N/10], p_num; bool vis[N]; void GetPrime(){ memset(vis,0,sizeof(vis)); vis[1] = 1; p_num = 1; for(int i = 2; i < N; i++){ if( !vis[i] ) prime[p_num++] = i; for(int j = 1; (j<p_num)&&(prime[j]*i<N); j++){ vis[ prime[j]*i ] = 1; if( i%prime[j] == 0 ) break; } } prime[1] = 3, prime[2] = 4; // p_num = 1.2 * 10^6 // printf("%d\n", p_num ); } struct Matrix{ LL mat[2][2]; void zero(){memset(mat,0,sizeof(mat));} void unit(){ zero(); mat[0][0]=mat[1][1]=1; } }; Matrix mult( Matrix A, Matrix B, int mod ){ Matrix C; C.zero(); for(int i = 0; i < 2; i++){ for(int k = 0; k < 2; k++) for(int j = 0; j < 2; j++) C.mat[i][j] = (C.mat[i][j]+A.mat[i][k]*B.mat[k][j])%mod; } return C; } Matrix Pow( Matrix X, int n, int mod ){ Matrix res; res.unit(); while( n ){ if( n&1 ) res = mult(res,X,mod); X = mult(X,X,mod); n >>= 1; } return res; } Matrix A, T; void init_Matrix(){ A.mat[0][0] = A.mat[1][0] = 1; A.mat[0][1] = A.mat[1][1] = 0; T.mat[0][0] = 0; T.mat[0][1] = T.mat[1][0] = T.mat[1][1] = 1; } void print( Matrix t ){ for(int i = 0; i < 2; i++){ for(int j = 0; j < 2; j++) printf("%lld ", A.mat[i][j] ); puts(""); } } void solve(){ int k, x, m; scanf("%d%d%d", &k, &x, &m); int k_idx = prime[k], s_idx = k_idx; // printf("k_idx = %d\n", k_idx ); init_Matrix(); A = mult( Pow(T,k_idx-1,x), A, x ); // print(A); for( ;; s_idx++ ){ if( A.mat[0][0] == 0 ) break; //printf("A.mat[0][0] = %lld, [1][0] = %lld\n", A.mat[0][0], A.mat[1][0] ); A = mult( T, A, x ); } //printf("s_idx = %d\n", s_idx ); init_Matrix(); A = mult( Pow(T,s_idx-1,x*m), A, x*m ); printf("%lld\n", A.mat[0][0]/x ); } int main(){ GetPrime(); int T; scanf("%d", &T); while( T-- ){ solve(); } return 0; }
D Density of Power Network
题目描述那副图好复杂.不过题意和图没多大关系. 统计不重复的边.然后除以顶点N即可.
#include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<algorithm> using namespace std; const int N = 550; bool mp[N][N]; int a[N], b[N]; int main(){ freopen("1.in", "r", stdin); int T; scanf("%d", &T); while( T-- ){ int n, m; scanf("%d%d",&n,&m); memset(mp,0,sizeof(mp)); for(int i = 0; i < m; i++) scanf("%d", &a[i]); for(int i = 0; i < m; i++) scanf("%d", &b[i]); for(int i = 0; i < m; i++) mp[ a[i] ][ b[i] ] = mp[ b[i] ][ a[i] ] = 1; int cnt = 0; for(int i = 1; i <= n; i++) for(int j = i; j <= n; j++) cnt += mp[i][j]; printf("%.3lf\n", 1.0*cnt/n ); } return 0; }
E Egg Painting
计算几何只会水题版本...太神了不太会...
F Friends
N才100, 枚举两个没关联的, 然后看其相同朋友是否大于等于K, 若是则连接. 要注意的是, 连接后还有可能给其他人造成影响.所以需要重复的搞. 第二组样例看的出来.
#include<cstdio> #include<cstring> #include<cstdlib> #include<vector> #include<algorithm> using namespace std; const int N = 110; bool mp[N][N]; vector<int> Q[N]; int n, m, k; int main(){ freopen("1.in","r",stdin); int T; scanf("%d", &T); while( T-- ){ scanf("%d%d%d", &n,&m,&k); memset( mp, 0, sizeof(mp)); for(int i = 0; i < n; i++) Q[i].clear(); for(int i = 0; i < m; i++){ int a, b; scanf("%d%d",&a,&b); mp[a][b] = mp[b][a] = true; Q[a].push_back(b); Q[b].push_back(a); } int res = 0; while( 1 ){ int cnt = 0; for(int a = 0; a < n; a++){ for(int b = a+1; b < n; b++){ if( mp[a][b] == false){ int t = 0; for(int i = 0; i < (int)Q[a].size(); i++){ int c = Q[a][i]; if( mp[b][c] == true ) t++; } if( t >= k ){ mp[a][b] = mp[b][a] = true; Q[a].push_back(b); Q[b].push_back(a); cnt++; } } } } res += cnt; if( cnt == 0 ) break; } printf("%d\n", res ); } return 0; }
G Give Me Your Hand
概率DP一直很渣.
H Hard to Play
别想太复杂.. 可以证明, 因为次数累积, 则分数大的放后面连续必定最大, 反之则最小.
#include<cstdio> int main(){ int T; scanf("%d", &T); while( T-- ){ int A, B, C; scanf("%d%d%d", &A,&B,&C); int res = 0, ans = 0; for(int i = 1, t = 0; i <= A+B+C; t++, i++ ) if( i > B+C ) res += 300*( t*2+1 ); else if( i > C) res += 100*( t*2+1 ); else res += 50*( t*2+1 ); for(int i = 1, t = 0; i <= A+B+C; t++, i++ ) if( i <= A ) ans += 300*( t*2+1 ); else if( i <= A+B ) ans += 100*( t*2+1 ); else ans += 50*( t*2+1 ); printf("%d %d\n", ans, res ); } return 0; }
I In 7-bit
神描述. 虽然我没看懂...但是队伍中有jian1573这样的大神.....
#include <iostream> #include <cmath> #include <cstring> #include <cstdio> #include <string> #include <stdlib.h> #include <algorithm> using namespace std; typedef long long LL; const LL Mod= 1e9+7; const int M=3000050; char s[M]; int T; int main( ) { scanf("%d", &T); getchar(); while(T--){ gets(s); int len=strlen(s); if (len == 0) { puts("00"); continue; } int t=len; while(t){ int ans= (t&0x7f); t >>= 7; if( t>0 ) ans |= 0x80; printf("%02X",ans); } for( int i=0; i<len; ++ i ){ printf("%02X", s[i]); } puts(""); } return 0; }
J Java Beans
围成一圈,求连续M个最大值....N <= 100...M <= 100... 除了暴力我真心不知道还能干嘛.
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int N = 210; const int inf = 0x3f3f3f3f; int n, m; int a[N]; int main(){ int T; scanf("%d", &T); while(T--){ scanf("%d%d", &n,&m); for(int i = 0; i < n; i++) scanf("%d", &a[i]); int res = 0; for(int i = 0; i < n; i++){ int t = 0; for(int j = 0; j < m; j++){ t += a[ (i+j)%n ]; } res = max( res, t ); } printf("%d\n", res); } return 0; }
K Kindergarten Election
正面贪心, 无法得到正确解. 变量过多, 通过枚举部分变量然后确定其他变量.
枚举 1获得票数x. 然后 处理其他票数大于X的,降至X-1,则必然只能加到1去. 1票数超过x则不合法, 若1的小于x,则再贿赂最小花费的人,加到x..然后求出最小的cost.即是最终答案.
有个地方我们没有处理, 就是当1获得x票,其他人都是x-1票.这个时候,因为1本身要投一票给别人. 可能会有其他N-1个都含有X-1票,这时候会发现1拿X票不一定赢, 其实简单推下就能发现这种情况是不存在的, 若存在, 则这时候有 x + (N-1)*(x-1) + 1 = N , 然后变换下得到 x = 2 - 2/N, 因为N>=3, 则 x必定为浮点数,而非整数. 所以此时的X是不存在的. 所以此情况无需考虑. 然后代码写起来就很短了.
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; const int N = 200; const int inf = 0x3f3f3f3f; int f[N], c[N], d[N]; int n; int tf[N], td[N]; bool vis[N]; int GetMax(){ // temp int t = -1; for(int i = 2; i <= n; i++) t = max( t, td[i] ); return t; } int update(int x){ // tmp_father and tmp_depth td[ tf[x] ]--; td[1]++; tf[x] = 1; return c[x]; } int maintain(int tar){ int cost = 0; bool flag = false; for(int i = 2; i <= n; i++){ if( td[i] < tar-1 ) flag = true; } if( flag ) return cost; else{ int t = inf, pos; for(int i = 2; i <= n; i++){ if( (td[ tf[i] ] == tar-1) && (t > c[i]) ) t = c[i], pos = i; } cost += update(pos); return cost; } } int cao(int tar){ int cost = 0, k; for(int i = 1; i <= n; i++) td[i] = d[i], tf[i] = f[i]; k = GetMax(); while( k >= tar ){ int t = inf, pos; for(int i = 2; i <= n; i++){ if( (tf[i]!=1) && (td[tf[i]]>=tar) && (t>c[i]) ) t = c[i], pos = i; } cost += update( pos ); k = GetMax(); } if( td[1] > tar ) return inf; else{ while( td[1] < tar ){ int t = inf, pos; for(int i = 2; i <= n; i++) if( (tf[i]!=1) && (t > c[i]) ) t = c[i], pos = i; cost += update(pos); } // cost += maintain( tar ); return cost; } } int gao(){ int res = inf; for(int i = 2; i <= n-1; i++){ int t = cao(i); // printf("i = %d, t = %d\n", i, t); res = min( res, t ); } return res; } int main(){ int T; scanf("%d", &T); while( T-- ){ scanf("%d", &n); memset( d, 0, sizeof(d)); memset( c, 0, sizeof(c)); for(int i = 2; i <= n; i++){ scanf("%d", &f[i] ); d[ f[i] ]++; } for(int i = 2; i <= n; i++){ scanf("%d", &c[i] ); } printf("%d\n", gao() ); } return 0; }