您的位置:首页 > 其它

广师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;
}

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: