A:http://codeforces.com/contest/1360/problem/A
题意:
用最小正方形,容下两个相同矩形。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
int main()
{
int t;
cin>>t;
while(t--)
{
int a,b;
cin>>a>>b;
if(a>b)
swap(a,b);
if(a*2==b)
cout<<b*b<<endl;
else
{
if(2*a>b)
cout<<2*a*2*a<<endl;
else
cout<<b*b<<endl;
}
}
}
B:http://codeforces.com/contest/1360/problem/B
题意:
将n个数分成两组,要求一组的最大值减去另一组的最小值的绝对值最小。
解析:
直接sort然后找最小间距
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
int a[56];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
int minn=1e9;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=2;i<=n;i++)
minn=min(minn,a[i]-a[i-1]);
cout<<minn<<endl;
}
}
C:http://codeforces.com/contest/1360/problem/C
题意:
给出n个数,要求进行两两配对,配对的两个数满足%2相等或者差值为1。
问是否能把所有数配对成功。
解析:
题中已经表示:n为偶数,所以偶数的数目和奇数的数目的奇偶性是相同的。
如果数目均为偶数,那么所有偶数内部配,奇数内部配,是可以包含所有数的。
如果数目均为奇数,那么遍历一下,是否存在差值为1的两个数,如果有,一定为一奇一偶,数目中把它俩划掉,也是正好可以进行两两配对的。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
int a[80];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
int j=0,o=0,d=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]%2!=0)
j++;
else
o++;
}
sort(a+1,a+1+n);
for(int i=2;i<=n;i++)
{
if(a[i]-1==a[i-1])
{
d++;
}
}
if(j%2==0&&o%2==0)
cout<<"YES"<<endl;
else
{
if(d>0)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}
}
D:http://codeforces.com/contest/1360/problem/D
题意:
给出n和k,在[1,k]中找到一个x,使得n%x==0而且n/x最小。
解析:
直接遍历的话会超时。既然是找n的因子,那么直接在sqrt(n)以内找就可以了,复杂度为O(sqrt(n))。
通过sqrt(n)左边因子来顺便判断右边
找到的每一个因子,要满足<=k,并不断更新x的最大值,就能保证n/x最小。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll minn=1e9;
int main()
{
int t;
cin>>t;
while(t--)
{
ll n,k;
cin>>n>>k;
minn=1e9;
if(k>=n)
cout<<"1"<<endl;
else
{
ll maxx=0;
for(ll i=1;i*i<=n;i++)
{
if(n%i==0&&i<=k)
{
if(n/i<=k)
maxx=max(maxx,n/i);
maxx=max(maxx,i);
}
}
cout<<n/maxx<<endl;
}
}
}
E:http://codeforces.com/contest/1360/problem/E
题意:
左边和上面发射炮弹,如果遇到阻碍,那么停住,标为1,而且上一个位置也标为1。给出一个情况,判定是否合法。
解析:
刚开始想复杂了,对于一个1来说,它的下方,要么是边界,要么是1,同理,它的右边也一样。
所以如果一个1的下方和右方满足其中一个条件,就是合法的。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 60;
char mp[maxn][maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>mp[i];
int ok = 0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(i<n-1&&j<n-1&&mp[i][j]=='1')
{
if(mp[i+1][j]!='1'&&mp[i][j+1]!='1')
{
ok=1;break;
}
}
}
if(ok)
cout<<"NO"<<endl;
else
cout<<"YES"<<endl;
}
}
F:http://codeforces.com/contest/1360/problem/F
题意:
给出n个字符串,是否存在一个串,与这n个字符串最多只有一个位置不相同。
解析:
直接暴力模拟
mp[1~n][1~m]记录每一个字符串。
s[i]记录第一个字符串的每一位。
以第一个字符串为基准,对它修改每一位,并check(),看是否合法:与其他字符串的不同位置数<=1
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 60;
char mp[12][12];
char s[12];
int n , m ;
bool check()
{
for(int i=1;i<n;i++)
{
int cnt=0;
for(int j = 0 ; j < m ; j++)
{
if(mp[i][j]!=s[j])
cnt++;
}
if(cnt>1)
return false;
}
return true;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>mp[i];
for(int i=0;i<m;i++)
s[i]=mp[0][i];
int ok = 1;
for(int i=0;i<m;i++)
{
for(char j='a';j<='z';j++)
{
s[i]=j;
if(check())
{
ok=0;
break;
}
}
if(!ok)
{
// cout<<s<<"-"<<endl;
break;
}
s[i]=mp[0][i]; //记得还原!因为每次只能修改一处
}
// for(int i=0;i<m;i++)
// cout<<s[i];
// cout<<endl;
s[m]='\0';
if(ok)
cout<<"-1"<<endl;
else
cout<<s<<endl;
}
}
G:http://codeforces.com/contest/1360/problem/G
题意:
是否存在一个n*m的矩阵,满足每行有a个1,每列有b个1。
解析:
如果一个位置变成了1,那么,它所在的行,列,都要+1。
那么每次同时+1,就变成了n*a==m*b了。满足这个条件,才可以构造。
构造的时候,肯定是尽量平均铺的。
很明显,全扎堆在一起,行满足,列也未必满足。
平均铺的代码:
int id=0;
for(int i=0;i<n;i++)
{
for(int j=id;j<id+a;j++)
mp[i][j%m]=1;//%m防越界
id+=a;
}
记得初始化,否则样例都过不了:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=60;
int mp[maxn][maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
int n , m , a , b;
memset(mp,0,sizeof(mp));//初始化
cin>>n>>m>>a>>b;
if(n*a!=m*b)
cout<<"NO"<<endl;
else
{
int id=0;
for(int i=0;i<n;i++)
{
for(int j=id;j<id+a;j++)
mp[i][j%m]=1;
id+=a;
}
cout<<"YES"<<endl;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
cout<<mp[i][j];
cout<<endl;
}
}
}
}
H:http://codeforces.com/contest/1360/problem/H
题意:
2^m个只含0,1的串,删除掉n个所给串,求排序后处于中位数的那个串。
解析:
01串,其实就是个二进制,所以可以先把它们转化为十进制,也是符合字典序排序的。
总串数为偶数:如果删除的数<中位数,那么中位数的位置要后移;
总串数为奇数:如果删除的数>中位数,那么中位数的位置要前移。
明确了这一点,那么就可以直接进行模拟了。
用vector来储存需要删除的数,用map来标记是否被删除。
逐一删除每一个串,每次求出未删除串中的中位数来。
最后再转化为二进制,倒序输出
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=60;
int mp[maxn][maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
vector<ll>v;
ll n , m ;
cin>>n>>m;
string s;
for(int i=1;i<=n;i++)
{
cin>>s;
ll sum=0;
for(int j=0;j<m;j++)
sum=sum*2+s[j]-'0'; //从前往后来转十进制
v.push_back(sum);
}
ll all=1ll<<m; //2^m
ll md=(all-1)/2;
map<ll,ll>mp;
for(int i=0;i<n;i++)
{
mp[v[i]]=1;
if(all%2==0)
{
if(v[i]<=md)
{
md++;
while(mp[md]) //因为可能md已经被删除了。
md++;
}
}
else
{
if(v[i]>=md)
{
md--;
while(mp[md])
md--;
}
}
all--;
}
// cout<<md<<endl;
string ch;
for(int i=0;i<m;i++) //转二进制操作
{
if(md>>i&1)
ch+='1';
else
ch+='0';
}
reverse(ch.begin(),ch.end()); //倒序操作<algorithm>
cout<<ch<<endl;
}
}
记录一下两个容易混的知识点:
右移 >>
左移 <<
左移几 就是乘以 2的几次方 左移三位 就是 乘以8
右移几 就是除以 2的几次方