2017 计蒜之道 初赛 第一场 A题B题





阿里九游开放平台近日上架了一款新的益智类游戏——成三棋。成三棋是我国非常古老的一个双人棋类游戏,其棋盘如下图所示:

成三棋的棋盘上有很多条线段,只能在线段交叉点上放入棋子。我们可以用坐标系来描述棋盘:

如果一条线段上的三个交叉点都被同一玩家的棋子占据的话,则称这条线段被该玩家 成三。现在,小红和小明两人在游戏平台上下棋,其中小红的棋子是黑色的。请你帮小红计算他成三的线段数。

样例对应的棋盘如下:

输入格式

输入第一行两个整数 n,m(3 \le n, m \le 9)n,m(3n,m9)nn 表示小红的棋子数,mm 表示小明的棋子数。

接下来 nn 行输入小红的棋子坐标。

接下来 mm 行输入小明的棋子坐标。

输入保证坐标合法,并且棋子之间不重合。

输出格式

输出小红成三的线段数。

样例输入
6 3
-1 0
-2 0
-3 0
-1 -1
-1 1
1 0
0 2
0 3
2 2
样例输出
2

直接暴力枚举

package 计蒜之道初赛第一场;
import java.util.Scanner;


public class 计蒜之道 {

	/**
	 * @param args
	 */
	static int map[][]=new int[200][200];
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scan=new Scanner(System.in);
		int n,m;
		int ans=0;
		int t;
		while(((n=scan.nextInt())!=0)&&((m=scan.nextInt())!=0)){
			ans=0;
		    for(int i=0;i<200;i++){
		    	for(int j=0;j<200;j++){
		    		map[i][j]=0;
		    	}
		    }
			for(int i=0;i<n;i++){
				int a=scan.nextInt();
				int b=scan.nextInt();
				map[100+a][100+b]=1;
			}
			for(int i=0;i<m;i++){
				int c=scan.nextInt();
				int d=scan.nextInt();
			}
			t=1;//内圈
			int d=100;
			if(map[d+t][d-t]==1&&map[d+t][d]==1&&map[d+t][d+t]==1){
				ans++;
			}
			if(map[d-t][d-t]==1&&map[d-t][d+t]==1&&map[d-t][d]==1){
				ans++;
			}
			if(map[d-t][d+t]==1&&map[d][d+t]==1&&map[d+t][d+t]==1){
				ans++;
			}
			if(map[d-t][d-t]==1&&map[d][d-t]==1&&map[d+t][d-t]==1){
				ans++;
			}
			t=2;//中圈
			if(map[d+t][d-t]==1&&map[d+t][d]==1&&map[d+t][d+t]==1){
				ans++;
			}
			if(map[d-t][d+t]==1&&map[d-t][d-t]==1&&map[d-t][d]==1){
				ans++;
			}
			if(map[d-t][d+t]==1&&map[d][d+t]==1&&map[d+t][d+t]==1){
				ans++;
			}
			if(map[d-t][d-t]==1&&map[d][d-t]==1&&map[d+t][d-t]==1){
				ans++;
			}
			t=3;//外圈
			if(map[d+t][d-t]==1&&map[d+t][d]==1&&map[d+t][d+t]==1){
				ans++;
			}
			if(map[d-t][d+t]==1&&map[d-t][d-t]==1&&map[d-t][d]==1){
				ans++;
			}
			if(map[d-t][d+t]==1&&map[d][d+t]==1&&map[d+t][d+t]==1){
				ans++;
			}
			if(map[d-t][d-t]==1&&map[d][d-t]==1&&map[d+t][d-t]==1){
				ans++;
			}
			//轴
					if(map[d+1][d]==1&&map[d+2][d]==1&&map[d+3][d]==1) 
						ans++;
					if(map[d-1][d]==1&&map[d-2][d]==1&&map[d-3][d]==1)  //左 
						ans++;
					if(map[d][d+1]==1&&map[d][d+2]==1&&map[d][d+3]==1) //shang 
						ans++;
					if(map[d][d-1]==1&&map[d][d-2]==1&&map[d][d-3]==1) 
						ans++;
			System.out.println(ans);
		}
		
		
	}

}

阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 DNA 碱基序列 tt,判断它在另一个根据规则生成的 DNA 碱基序列 ss 中出现了多少次。

首先,定义一个序列 ww

\displaystyle w_{i} = \begin{cases}b, & i = 0\\(w_{i-1} + a) \mod n, & i > 0\end{cases}wi={b,(wi1+a)modn,i=0i>0

接下来,定义长度为 nn 的 DNA 碱基序列 ss(下标从 00 开始):

\displaystyle s_{i} = \begin{cases}A , & (L \le w_{i} \le R) \land (w_{i}\ \mathrm{mod}\ 2 = 0)\\T , & (L \le w_{i} \le R) \land (w_{i}\ \mathrm{mod}\ 2 = 1)\\G , & ((w_{i} < L) \lor (w_{i} > R)) \land (w_{i}\ \mathrm{mod}\ 2 = 0)\\C , & ((w_{i} < L) \lor (w_{i} > R)) \land (w_{i}\ \mathrm{mod}\ 2 = 1)\end{cases}si=A,T,G,C,(LwiR)(wi mod 2=0)(LwiR)(wi mod 2=1)((wi<L)(wi>R))(wi mod 2=0)((wi<L)(wi>R))(wi mod 2=1)

其中 \land 表示“且”关系,\lor 表示“或”关系,a\ \mathrm{mod}\ ba mod b 表示 aa 除以 bb 的余数。

现给定另一个 DNA 碱基序列 tt,以及生成 ss 的参数 n , a , b , L , Rn,a,b,L,R,求 tt 在 ss 中出现了多少次。

输入格式

数据第一行为 55 个整数,分别代表 n , a , b , L , Rn,a,b,L,R。第二行为一个仅包含ATGC的一个序列 tt

数据保证 0 < a < n,0<a<n, 0 \le b < n,0b<n, 0 \le L \le R < n,0LR<n, |t| \le 10^{6}t106a,na,n 互质。

对于简单版本,1 \leq n \leq 10^{6}1n106

对于中等版本,1 \leq n \leq 10^{9}, a = 11n109,a=1

对于困难版本,1 \leq n \leq 10^{9}1n109

输出格式

输出一个整数,为 tt 在 ss 中出现的次数。

样例说明

对于第一组样例,生成的 ss 为TTTCGGAAAGGCC

样例输入1
13 2 5 4 9
AGG
样例输出1
1
样例输入2
103 51 0 40 60
ACTG
样例输出2
5
裸kmp字符串匹配

#include<stdio.h>
#include<string.h>
typedef long long ll;
ll n,a,b,L,R,ans;
char ts[1010101];
int f[1001000];
char make(int wi)
{
	if(L<=wi&&wi<=R)
	{
		if(wi%2==0)
			return 'A';
		else
			return 'T';
	}
	else
	{
		if(wi%2==0)
			return 'G';
		else
			return 'C';
	}
}
void getfail(char p[],int f[]) //字符串p自我匹配   
{  
    int len=strlen(p);
    f[0]=f[1]=0;
    for(int i=1;i<len;i++)
    {
        int j=f[i];
        while(j&&p[i]!=p[j])  
            j=f[j];
        if(p[i]==p[j])  
            f[i+1]=j+1;//多匹配到了一个字符  
        else   
            f[i+1]=0;//该字符配不上
    }   
}  
int find(char*P, int*f)//p去匹配字符串T   
{    
    int m = strlen(P);    
    getfail(P, f);  //得出部分匹配表 
    int j = 0;  //短串的下标 
    for(int i = 0; i < n; i++) //长串下标
    {
        while(j && P[j] != make((b+i*a)%n))//突然失配了
        {
            j = f[j];  //j往回退,直到0或者上一个字符相等的位置
        }
        if(P[j] == make((b+i*a)%n))
        {
            j++;  //匹配了一个字符,j++   
        }    
        if(j == m)  //短串匹配到头了
        {
        	ans++;
            //return i - m + 1;//返回成功匹配的起点字符位置
        }
    }
    return -1;    
}   


int main()
{

	while(~scanf("%lld%lld%lld%lld%lld",&n,&a,&b,&L,&R))
	{
		scanf("%s",ts);
		ans=0;
		find( ts, f);
		
		printf("%lld\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值