1 题目
(此题来源牛客网网易2018秋招笔试真题)
1.1 题目描述
有一个长度为N的正整数数列A = {A[1],A[2],A[3]...,A[n]}。
对该数列进行重新排列,使数列A满足所有的A[i]*A[i+1](1 <= i <= N-1)都是4的倍数。
判断某一数列重新排列之后是否满足以上要求。
1.2 输入描述
输入第一行为需要判断的数列个数t(1 <= t <= 10),
接下来每两行,第一行表示数列长度n(1 <= n <= 10^5),第二行为n个正整数A[i](1 <= A[i] <= 10^9)。
1.3 输出描述
若满足输出Yes,否则输出No。
1.4 输入样例
2
3
1 10 100
4
1 2 3 4
1.5 输出样例
Yes
No
2 问题分析
最简单粗暴方法,穷举所有可能,对输入数组进行重排列,考虑所有可能,然后一个个进行测试。
结果毫无疑问会超时。。。
进行分析数组,数的大小最小为1,省去了考虑0的麻烦,因为0可以被任何非0数整除。
1 如果数列中某个数是4的倍数,则它左右A[i-1]*A[i]和A[i]*A[i+1]都可以被4整除,通俗来讲,若数列中有4的倍数的数,则它可以救两个非4倍的数。4倍数个数记作 n4。2个四倍数可以救3个,3个4倍数可以救4个,n4个四倍数可以救n4+1个。
2 如果数列中某个数是2的倍数,且不为4的倍数,比如6 10 18等,则这样任意两个2倍数放在一起就可以被4整除。这样仅能为2整除的2倍数个数记作 n2。因为两个2倍数可以合成为4倍数,若n2为奇数,则还剩一个没有匹配。但是,当仅2倍数为偶数时,就1 2 6 3而言,即使把两个2倍数放在一块,2倍数两边需要被救(6 3组合不可以被4整除,1 2组合也不可以被4整除);当仅2倍数为奇数时,例如3 6 2 10 7,2倍数两边还是需要被救(3 6和10 7组合),被救个数取决于非4被数非2倍数的总数,即下面的n1。
3 若不是4倍数也不是仅2倍数,记作 n1,n1 = n - n4 - n2。
若n2为0,则4倍数可以n4+1个数,若n2 > 0,则n4可以救n4个数,则可以输出Yes,否则输出No。n1为要被救的数,(n2&1)也是要被救的数。(n2&1)判断是否为奇数。
3 代码编写
#include <iostream>
using namespace std;
void test(){
int t; //数列的个数
cin>>t;
while(t--){
int n;
cin >> n;
int* A = new int[n+1]; //脚标从1开始
int n4 = 0; //4倍数
int n2 = 0; //仅2倍数
int n1 = 0; //仅1倍数
for(int i = 1;i <= n;i++)
cin>>A[i];
for(int i = 1;i <= n;i++){
if(A[i] % 4 == 0) //4倍数
n4++;
else if((A[i]&1) == 0) //仅2倍数
n2++;
else
n1++; //仅1倍数
}
if( n2 > 0 ){ //至多可以救n4个数
if(n1 <= n4)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
else{ //至多可以救n4+1个数
if(n1 <= n4+1)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
delete A;
}
}
int main()
{
test();
return 0;
}