【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”。
有四种移动方法:
(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。
这里定义子序列是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)
第一行:一个整数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 ;
}