2017年11月20日周赛五

【A】多米诺骨牌
题目描述
给你一个M×N的矩形,和2×1的多米诺骨牌。求能往矩形里放最多的多米诺骨牌的数量。
输入

第一行:T,测试实例数。

第二行两个整数M和N。 (1≤M≤N≤10^9).

输出
一个整数,表示放入的多米诺骨牌的最大数量。
样例输入
2
2 4
3 3
样例输出
4
4
令a=M/2,a表示一列里可以放的多米诺牌数量;令sum=a*N,sum表示N列中放的多米诺牌的总数;
如果是奇数行,则还需判断最后一行中可放入多米诺牌的数量,将其加入sum即可求得最多米诺牌总数。
#include<stdio.h>
typedef long long ll ;
int main() {
    ll t ,N , M ;//输入MxN大小的矩形,已知多米诺骨牌大小为2x1
    ll sum=0, a=0 ;//可以看做M行N列,多米诺牌大小占2行1列
    scanf("%lld" , &t ) ;
    while ( t-- ) {
    	scanf("%lld%lld", &M , &N) ;
        a = M / 2 ;
        sum = a * N ;
        if ( M % 2 == 1 ) sum += ( N / 2 ) ;
        printf("%lld\n", sum ) ;
    }
    return 0 ;
}

【B】移动坐标
题目描述
给你两个点A、B,和固定移动距离(x,y),问是否可以通过移动A点若干次最终到B点。

有四种移动方法:
(a,b)->(a+x,b+y);
(a,b)->(a+x,b-y);
(a,b)->(a-x,b+y);
(a,b)->(a-x,b-y);

如果可以输出“YES”,否则输出“NO”。
输入

第一行:T,测试实例个数:

第二行:四个整数。x1,y1,x2,y2。分别是A点的坐标和B点的坐标。 - 10^5 ≤ x1, y1, x2,y2 ≤ 10^5

第三行:两个整数。x,y是固定移动距离    (1 ≤ x, y ≤ 105

输出
“YES”或者“NO”。
样例输入
2
0 0 0 6
2 3
1 1 3 6 
1 5
样例输出
YES
NO

先保证两个点的横坐标差一定是a的倍数,纵坐标差一定是b的倍数。
t1=abs(x-x2)/a;  t1表示最少需要多少步起点的横坐标可以达到终点的横坐标
t2=abs(y-y2)/b; t1表示最少需要多少步起点的纵坐标可以达到终点的纵坐标
t1和t2的差必须是偶数,我们把坐标移动不要当做横纵坐标一起移动。
比如
第一步:(x,y)->(x a,y b);
第二步:(x a,y b)->(x 2a,y); 
即可以在纵坐标不变的情况下,在横坐标上进行平移,但必须平移2a步。
可以思考一下
#include<stdio.h>
#include<stdlib.h>
int main()
{
    int x,y,x2,y2,a,b,flag,t1,t2,t;
    scanf("%d",&t);
    while(t--)
    {
        flag=1;
        scanf("%d%d%d%d%d%d",&x,&y,&x2,&y2,&a,&b);
        if(abs(x-x2)%a==0&&abs(y-y2)%b==0)
        {
            t1=abs(x-x2)/a;
            t2=abs(y-y2)/b;
            if(abs(t1-t2)%2==0)
            {
                printf("YES\n");
                flag=0;
            }
        }
        if(flag==1)printf("NO\n");
    }
    return 0;
}


【C】01串
题目描述
给你一个字符串,长度为n,只有0和1组成,简称01串。我们可以在串中选择一个起点和终点进行区间翻转,即区间中的0变成1,1变成0。翻转后得到了一个新的01串。且要求翻转后得到的新的01串中的01子序列最长。
这里定义子序列是01间隔的。(子序列就是在原来序列中找出一部分(可以不连续)组成的序列)。
比如000100010 这个串中01间隔的子序列的长度为5.即01010
比如1011。最长子序列长度为3,即101。

比如1101101 最长子序列长度为5。即10101。

举个栗子:
长度为8的10000011,可以变成10111011或10100011或10110011等等,翻转后最长长度为5,即10101。
长度为2的10,可以翻转整个串,变为01,子串最长长度为2

输入

第一行:T,测试实例个数

第二行:一个n表示01串的长度。(1≤n≤10000)

第三行:输入一个01串。

输出
一个整数,表示翻转后最长子序列的长度。
样例输入
1
8
10000011
样例输出
5

思路一:
1、通过枚举发现,在原串中如果有一段长度大于3的连续相等子串:10000000001-------------->10100000001,那么其解ans=原串最长子串长度2.
2、再通过枚举发现,在原串中有一段长度为2的连续相等的子串:110101---------->010101,那么其解ans=原串最长子串长度1.
以上两种方案都是通过改变原串某一个字符增加长度的,接下来我们再枚举一下通过区间翻转的情况带来增加的情况:
3、再通过枚举发现,在原串中假如有两段以及两段以上的长度为2的连续相等子串:1100---------------->1010,那么其解ans=原串最长子串长度2.
#include<stdio.h>
char a[1000010];
int main()
{
    int n,cnt,cnt2,ans,maxcnt,i,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        scanf("%s",a);
        ans=1;
        maxcnt=0;
        cnt=1;
        cnt2=0;
        for(i=0;i<n-1;i++)
        {
            if(a[i]==a[i+1]) cnt++;
            else
            {
                if(cnt==2) cnt2++;
                cnt=1;
                ans++;
            }
            if(cnt>maxcnt) maxcnt=cnt;
        }
        if(cnt==2) cnt2++;
        if(maxcnt>=3) ans+=2;
        else if(maxcnt==2 && cnt2>1) ans+=2;
        else if(maxcnt==2 && cnt2==1) ans+=1;
        printf("%d\n",ans);
    }
    return 0;
}

思路二:
先求出原串的01子串长度:len
可以发现答案是 min(len+2,n)。
可以结合思路1的三种情况思考一下。
#define N 20000
char s[N];
int main()
{
    int n, T;
    int maxi, ans;
    cin >> T;
    while(T--) {
        cin >> n >> s;
        int flag = 0;
        ans = 1;
        for(int i = 0; i < n - 1; i++)
            if(s[i] != s[i+1])
                ans++;
        cout << min(ans + 2, n) << endl;
    }
    return 0;
}
【F】互质
题目描述
给你n个元素的序列,要求在其中插入最少的数,使得序列中任意两个相邻元素互质。
求插入的数的最少的数量。
输入
第一行:整数T,测试实例个数。
第一行:一个整数n,表示序列元素个数。  (1≤n≤1000) 
第二行:n个整数ai,用空格隔开,表示序列中的n个元素。  (1≤ai≤10^9)
输出
一个整数,表示最小插入数量。
样例输入
2
3
2 7 28
4
1 2 3 4
样例输出
1
0

因为1和任何数互质。

所以只需要求出相邻的不互质的个数即可,把1插入进去就好

#include<stdio.h>
typedef long long ll ;
ll a[1010] ;
ll gcd( ll x , ll y ) {
	if( !y ) return x ;
	return gcd( y , x%y ) ;
}
int main() {
	ll t , n ;
	scanf("%lld" , &t ) ;
	while( t-- ) {
		ll d = 0 ;
		scanf("%lld" , &n ) ;
		for(int i=1 ; i<=n ; i++ ) scanf("%lld" , &a[i] ) ;
		for(int i=1 ; i<=n-1 ; i++ ) {
			if(gcd( a[i] , a[i+1] ) != 1) d++ ;
		}
		printf("%lld\n" , d ) ;
	}
	return 0 ;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值