广师2016ACM校赛解答报告
2016-04-11 22:23
369 查看
广师2016ACM校赛解答报告
由于出题的数据范围问题,导致了严重降低了套题的难度。
OJ网址:http://114.215.99.34/#/enter/home
A. A+B问题略。(我偶尔听到翼翔敲高精度,我是吓到了。赶紧提醒一下是INT范围)
B.最大公约数和最小公倍数,大家都过了,略。
C.
题目:
给定n个正整数,你的任务是将它们连接成一个最大的正整数。
思路:如果是根据比较第I个字符串跟第J个字符串的大小来直接比较贪心的话。是不会得到最优解的。(可惜我们没有这组数据。。)
例如:121 12 。最优解是12121 ,而上述的贪心算法是12112。并不能得到最优解。
正确的思路应该是,A[i]跟A[j]。列举拼接起来的两种情况,再比较大小。
代码如下:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std ; #define MAX 1005 class node { public : char str[MAX] ; node() { } }A[MAX]; bool cmp( const node & A , const node & B ) { char t1[MAX] , t2[MAX] ; int len1 = strlen(A.str) ; int len2 = strlen(B.str) ; //t1 int i = 0 ; for( i = 0 ; i<len1 ; i++ ) t1[i] = A.str[i] ; for( ; i < len1 + len2 ; i++ ) t1[i] = B.str[i - len1] ; //printf("i : %d\n",i); t1[i] = '\0' ; //t2 i = 0 ; for( i = 0 ; i<len2 ; i++ ) t2[i] = B.str[i] ; for( ; i < len1 + len2 ; i++ ) t2[i] = A.str[i - len2] ; t2[i] = '\0' ; //printf("i : %d\n",i); //printf("t1 : %s t2 :%s\n",t1,t2) ; return strcmp(t1,t2) > 0 ; } int main() { int n ; while( scanf("%d",&n) != EOF , n ) { for( int i = 0 ; i<n ; i++ ) scanf("%s",A[i].str) ; sort( A , A+n , cmp ) ; for( int i = 0 ; i<n ; i++ ) printf("%s",A[i].str) ; printf("\n"); } return 0; }
D.
题目:SX师兄在做一个视频音频分离中的项目,其中需要求一串二进制比特流中是否出现过特定的比特串,二进制比特流的长度( n <= 1*10^6 ) ,特定比特串的长度m ( m < 100)。如果出现过,输出YES;否者输出NO。
非新生组:裸KMP。新生组:暴力求解。
KMP代码如下:
#include<stdio.h> #include<string.h> void getFail( char *P , int * f ) { int m = strlen(P) ; f[0] = f[1] = 0 ; for( int i = 1 ; i<m ; i++ ) { int j = f[i] ; while( j&& P[i]!=P[j] ) j = f[j] ; f[i+1] = P[i] == P[j] ? j+1 : 0 ; } } void KMP( char * T , char *p , int * f ) { int n = strlen(T) ;int m = strlen(p) ; //printf("n :%d m :%d\n",n,m) ; getFail(p,f) ; int j = 0 ; for( int i = 0 ; i<n ; i++ ) { while( j && p[j] != T[i] ) j = f[j] ; if( p[j] == T[i] ) j++ ; if( j == m ) {printf("%d\n",i-m+1) ; return ;} } printf("-1\n") ; return ; } #define MAX 1000009 char str[MAX] ; char str2[1000] ; int f[1000] ; int main() { freopen("input5.txt","r",stdin) ; freopen("output5.txt","w",stdout); scanf("%s %s",str , str2); KMP(str , str2 , f ) ; return 0; } /* #include<stdio.h> #include<stdlib.h> #include<time.h> int main() { int i ; int cnt = 1000009 ; freopen("input5.txt","w",stdout) ; //printf("%d\n",cnt) ; for( i = 0 ; i<cnt ; i++ ) { char t ; int a = rand()%2 ; if( a % 2 == 0 ) t = '0' ; else t = '1' ; printf("%c",t) ; } printf("%c",'\0') ; printf("\n"); for( i = 0 ; i<100 ; i++ ) { char t ; int a = rand()%2 ; if( a % 2 == 0 ) t = '0' ; else t = '1' ; printf("%c",t) ; } printf("%c",'\0') ; printf("\n"); printf("20202\n"); return 0; } */ /* #include<stdio.h> #include<string.h> char str[1000000] ; int main() { freopen("input0.txt","r",stdin) ; scanf("%s",str) ; int len = strlen(str) ; printf("%d\n",len) ; scanf("%s",str) ; printf("%s\n",str) ; return 0; } */
E.
题目:
项目好不容易做完了。SX师兄听说COC很好玩。在宿友拉坑下,终于选择入坑了。谁知道一发不可收拾。
。。。
脑洞大开的师兄觉得,如果是玩家能自己控制兵那会多好啊。进入YY中。。。。(important)
假设有三个兵种,
1.天使,能给第i个士兵加血
2.不死士兵,拥有M滴生命值,永久失去攻击能力。生命值可以为负,所以不会死亡。
3.皮卡超人,拥有强大的单体伤害,能给第i个士兵造成K点伤害。
因为士兵的生命值确定了队伍的整体战斗力,所以,司令官会不时问你,从i到j的不死士兵的生命值之和是多少。
游戏共有三种操作:
操作1.天使对编号为i的士兵加K点血
操作 2.皮卡超人发起攻击,对第i个士兵造成K点伤害
操作 3.查询编号为i到j的士兵的生命值之和
思路:
本质就是单点修改+区间求和。算法是树状数组或者线段树。
代码:
#include<stdio.h> #define MAX 10005 int sum[MAX<<2] ; void PushUp( int rt ) { sum[rt] = sum[rt<<1] + sum[(rt<<1)|1] ; } void build(int l , int r , int rt ) { if( l == r ) { scanf("%d",&sum[rt]) ; return ; } else { int mid = (l+r)>>1 ; build( l , mid , rt<<1 ) ; build( mid+1 , r , (rt<<1)|1 ) ; PushUp(rt) ; } } void add( int l , int r , int rt , int od, int s ) { sum[rt] += od ; if( l == r ) return ; else { int mid = (l+r)>> 1 ; if( mid >= s ) add( l , mid , rt<<1 , od , s ) ; else add( mid + 1 , r , (rt<<1)|1 , od , s ) ; } } int query( int ql , int qr , int l , int r , int rt ) { //printf(" l :%d r :%d\n",l,r) ; if( ql <= l && r <= qr ) { // printf("rt :%d sum[rt] :%d\n",rt , sum[rt] ) ; return sum[rt] ; } else { int mid = (l+r) >> 1 ; int res = 0 ; if( ql <= mid ) res += query( ql , qr , l , mid , rt<<1 ) ; if( qr > mid ) res += query( ql , qr , mid+1 , r , (rt<<1)|1 ) ; //printf("res :%d\n",res) ; return res ; } } int main() { int m , n ; //freopen("input0.txt","r",stdin) ; //freopen("output0.txt","w",stdout ); while( scanf("%d %d",&n,&m) != EOF ) { build( 1 , n , 1 ) ; for( int i = 0 ; i<m ; i++) { char op[2] ; int a , b ; scanf("%s %d %d",op,&a,&b) ; if( op[0] == 'a' ) { add(1,n,1 ,b,a) ; } else if( op[0] == 'd' ) { add(1,n,1,b,a) ; } else if( op[0] == 'q' ) { printf("%d\n",query(a,b,1,n,1) ); } } } return 0; } /* #include<stdio.h> #include<stdlib.h> #include<time.h> int main() { int n = 10004 ; int m = 1000009 ; freopen("input0.txt","w",stdout ); printf("%d %d\n",n,m) ; srand( (unsigned int)time(NULL) ) ; for(int i = 0 ; i<n ; i++ ) { int t = rand()%100 + 100 ; printf("%d ",t) ; } for( int i = 0 ; i<m ; i++ ) { int a = rand()%3 ; if( a == 0 ) { int b = rand() % n + 1 ; int c = rand() % 50 + 1 ; printf("a %d %d\n",b,c) ; } else if( a == 1 ) { int b = rand() % n + 1 ; int c = rand() % 50 + 1 ; printf("d %d %d\n",b,c) ; } else { int b = rand() % n + 1 ; int c = rand() %n + 1 ; while( c < b ) c = rand() % n + 1 ; printf("q %d %d\n",b,c) ; } } return 0; } */
F题,字符串的数量改为5W以上了。
题意大概是说,对于一个字符串A,问能不能找到另外两个字符串B和C,使它拼成A。允许A=BC或A=CB。
最容易的就是暴力了吧。时间复杂度是O(n^3*len)。
5W的字符串数量肯定是不行的。
考虑到,字符串长度是相对很短的。所以,我们要用Trie树来实现优化。
所以,我们可以先构造一棵Trie树。
然后对于每一个字符串A,我们把字符串分为两段。分别为0~i , i~len。
然后我们再Trie树上找0~i和i~len这两段字符串是否都在Trie树上。如果是,那么字符串A,就满足题意了。这样子时间复杂度降到O(n*len^2)
代码如下:
#include<stdio.h> #include<stdlib.h> #include<string.h> #define MAXNODE 10000*101 #define NEXTSIZE 30 int value[MAXNODE] ; int Trie[MAXNODE][NEXTSIZE] ; int sz = 1 ; void build( char * s , int v ) { int u = 0 , n = strlen(s) ; for( int i = 0 ; i<n ; i++ ) { int c = s[i] - 'a' ; if( !Trie[u][c] ) { memset( Trie[sz] , 0 , sizeof(Trie[sz]) ) ; value[sz] = 0 ; Trie[u][c] = sz++ ; } u = Trie[u][c] ; //printf("u :%d\n",u) ; } value[u] = v ; } int query( char * s , char * e ) { int u = 0 ; //printf("s :%c e :%c\n",*s,*e) ; for( char * t = s ; t <= e ; t++ ) { //printf("%c",*t) ; int c = (*t) - 'a' ; if( !Trie[u][c] ) return 0 ; u = Trie[u][c] ; } //printf("\n"); if( value[u] == 1 ) return 1 ; else return 0 ; } char str[10000][200] ; int main() { int cnt = 0 ; //freopen("input.txt","r",stdin) ; while( scanf("%s",str[cnt]) != EOF ) { //printf("%s\n",str[cnt]); build(str[cnt] ,1); cnt++ ; } for(int i = 0 ; i<cnt ; i++ ) { int len = strlen(str[i]) ; for( int j = 0 ; j<len-1 ; j++ ) { //for( char *k = &(str[i][0]) ; k <= &(str[i][0] )+ j ; k++ ) printf("%c",*k) ; //printf("\n"); /* for( char *k = &(str[i][0]) + j+1; k<= &(str[i][0]) + len-1 ; k++ ) printf("%c",*k) ; printf("\n"); printf("\n");*/ if( query( &(str[i][0]) , &(str[i][0] )+ j ) ) if( query( &(str[i][0]) + j+1 , &(str[i][0]) + len-1 ) ) { printf("%s\n",str[i]) ; break ; } } } return 0; }
G题:
非新生是完全背包。新生是01背包。
这里要提醒一下,完全背包跟01背包的动态转移方程式一样的。关键的不同是在于第二层循环的递推方向。这里只放完全背包的代码:
#include<stdio.h> int dp[10005] ; int w[1005] ; int v[1005] ; int max( int a, int b ) { return a >b ? a : b ; } int main() { int n , W ; //freopen("input4.txt","r",stdin ) ; //freopen("output4.txt" , "w" ,stdout) ; while( scanf("%d %d",&n,&W) != EOF ) { for(int i = 1 ; i<=n ; i++ ) scanf("%d %d",&w[i] , &v[i]) ; //init for( int i = 0 ; i<= W ; i++ ) dp[i] = 0 ; //dp for( int i = 1 ; i<= n ; i++ ) { for( int j = w[i] ; j<=W ; j++ ) dp[j] = max( dp[j] , dp[j-w[i]] + v[i] ) ; } int res = 0 ; for(int i = 0 ; i<=W ; i++ ) res = max( res , dp[i] ); printf("%d\n",res) ; } return 0; } /* #include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> int main() { int n = 1000 ; int V = 10000 ; freopen("input4.txt","w",stdout) ; srand( (unsigned int) time (NULL) ) ; printf("%d %d\n",n,V) ; for( int i = 1 ; i<=n ; i++ ) { int a = rand()%V+1 ; int b = rand()%V+1 ; printf("%d %d\n",a,b) ; } return 0 ; } */
最后一题:
最短路最简单的一道题。
Dijkstra , SPFA , Floyd都可以过的。
这里就放用优先队列优化的Dijstra。
算法详情,大家百度。
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std ; #define MAX 1001 #define INF 9999999 struct node { int c ; int times ; bool operator < ( const struct node & A ) const { return times > A.times ; } }; int T,S,D ; int Map[MAX][MAX] ; int d[MAX] ; int lovecity[MAX] ; int n ; void init() { memset( Map , -1 , sizeof(Map) ) ; n = 0 ; } int read() { int res = scanf("%d %d %d",&T,&S,&D) ; if( res == EOF ) return EOF ; // printf("T : %d S : %d D : %d\n",T,S,D) ; for( int i = 0 ; i<T ; i++ ) { int a , b , t ; scanf("%d %d %d",&a,&b,&t ) ; n = max( n , max(a,b) ) ; if( Map[a][b] != -1 ) Map[a][b] = Map[b][a] = min( Map[a][b] , t ) ; else Map[a][b] = Map[b][a] = t ; } for( int i = 0 ; i<S ; i++ ) { int v ; scanf("%d",&v) ; Map[0][v] = 0 ; } for(int i = 0 ; i<D ; i++ ) scanf("%d",&lovecity[i]) ; return res ; } int Dijstra(int s ) { priority_queue<node> Q ; Q.push(node{s,0}) ; int vis[MAX] ; memset( vis , 0 , sizeof(vis) ) ; for(int i = 1 ; i<=n ; i++ ) d[i] = INF ; d[s] = 0 ; while( !Q.empty() ) { node now = Q.top() ; Q.pop() ; // printf("now.c : %d\n",now.c) ; if( vis[now.c] ) continue ; vis[now.c] = 1 ; for(int i = 1 ; i<=n ; i++ ) { int u = now.c ; if( Map[u][i] != -1 && d[i] > d[u] + Map[u][i] ) { d[i] = d[u] + Map[u][i] ; Q.push( node{i , d[u]} ) ; } } } int res = INF ; for(int i = 0 ; i<D ; i++ ) res = min( res , d[ lovecity[i] ] ) ; return res ; } int main() { init() ; //freopen("input0.txt","r",stdin) ; //freopen("output0.txt","w",stdout ) ; while( read() != EOF ) { // printf("pass\n"); int res = Dijstra(0) ; if( res == INF ) printf("-1\n") ; else printf("%d\n",res ) ; init() ; } return 0; } /* #include<stdio.h> #include<stdlib.h> #include<algorithm> #include<time.h> #include<string.h> using namespace std ; int main() { int t = 10 ; freopen("input0.txt","w",stdout) ; for( int i = 0 ; i<10 ; i++ ) { int T , S , D ; T = 500 ; S = 10 ; D = 10 ; printf("%d %d %d\n",T,S,D) ; for(int i = 1 ; i<=T ; i++ ) { int a , b , t ; a = rand()%1000+1 ; b = rand()%1000+1 ; while( a == b ) b = rand()%1000 + 1 ; t = rand()%100 + 1 ; printf("%d %d %d\n",a,b,t) ; } for(int i =1 ; i<=S ; i++ ) { printf("%d ",i) ; } printf("\n") ; int flag[1000] ; memset( flag , 0 , sizeof(flag) ) ; for( int i = 1 ; i<= D ; i++ ) { int a ; a = rand()%1000 + 1 ; if( flag[a] == 0 ) { flag[a] = 1 ; printf("%d ",a) ; } } printf("\n"); } return 0; } */
相关文章推荐
- document.ready和onload的区别----JavaScript文档加载完成事件(二)
- 吉大投票| 选出你心中的“孝心大学生”
- 有道理
- 【追求进步】数组中只出现一次的数字
- Keil问题及其解决
- java事务介绍
- 分治小结
- Redis命令-有序集合-zrange
- div展开与收起(鼠标点击)
- 如何使用Linux Epoll来进行网络程序开发(译文)
- 我的深圳真实驾考经历
- Hibernate与 MyBatis的比较
- laravel常用命令
- c++作业3
- 解决虚拟机vmware下REDHAT不能上网问题的操作步骤
- Spring 简单IOC实现
- 二分图知识点
- 初识Git
- linux下安装mysql
- sed命令详解