Codeforces Round #777 (Div. 2)
Codeforces Round #777 (Div. 2)
contest
\[630 \Longrightarrow 1005
\]
分讨题爬分讨题爬分讨题爬分讨题爬分讨题爬分讨题爬分讨题爬
problem A
$problem $
给定一个数 \(n\),要求构造一个数列,使得每一位上的数相加之和为 \(n\)。
在保证每两个相邻的数不同的前提下使这个数列组成的十进制数最大。
输出构造的数列。
$solution$
很明显用 \(1,2\) 构成数列时最优。
按照 \(n \mod 3\) 所得的值分类。
\[\begin{cases} 1212 \dots 12 (n \mod 3 =0)\\ \dots 21 (n \mod 3 = 1)\\\dots 12 (n \mod 3 = 2)\end{cases}
\]
时间复杂度 \(O(n)\)
$code$
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5;
int t,n,a[N],sum;
signed main(){
// freopen("A.in","r",stdin);
// freopen("A.out","w",stdout);
cin>>t;
while(t--){
cin>>n;sum=0;
if(n%3==0){
for(int i=1;i<=n/3;i++){
cout<<"21";
}cout<<endl;
}else if(n%3==1){
for(int i=1;i<=n/3;i++){
cout<<"12";
}cout<<1<<endl;
}else{
for(int i=1;i<=n/3;i++){
cout<<"21";
}cout<<2<<endl;
}
}cout<<endl;
return 0;
}
preblem B
$problem$
给定一个长为 \(n\),宽为 \(m\) 的01矩阵,询问是否出现极大子矩形有相交的现象。
$solution$
直接跑悬线法的预处理,然后暴力判断即可。
时间复杂度: \(O(n \times m)\)
$code$
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=110;
int T,n,sum,m,lft[N][N],rgt[N][N],up[N][N];int a[N][N],flag;string s;
signed main(){
// freopen("B.in","r",stdin);
// freopen("B.out","w",stdout);
std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;flag=true;
for(int i=1;i<=n;i++)
{
cin>>s;
for(int j=1;j<=m;j++)
{
a[i][j]=(s[j-1]-'0');a[i][j]=!(a[i][j]);
lft[i][j]=rgt[i][j]=j;up[i][j]=1;
}
}
for(int i=1;i<=n;i++)
for(int j=2;j<=m;j++)
if(a[i][j]==a[i][j-1]&&a[i][j]==0) lft[i][j]=lft[i][j-1];
for(int i=1;i<=n;i++)
for(int j=m-1;j>=1;j--)
if(a[i][j]==a[i][j+1]&&a[i][j]==0) rgt[i][j]=rgt[i][j+1];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i>1&&a[i][j]==a[i-1][j]&&a[i][j]==0)
{
lft[i][j]=max(lft[i-1][j],lft[i][j]);
rgt[i][j]=min(rgt[i-1][j],rgt[i][j]);
up[i][j]=up[i-1][j]+1;
}
}
}
for(int i=2;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]==a[i-1][j]&&a[i][j]==0){
if(lft[i][j]!=lft[i-1][j]||rgt[i][j]!=rgt[i-1][j]){
flag=false;
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=2;j<=m;j++){
if(a[i][j]==a[i][j-1]&&a[i][j]==0){
if(lft[i][j]!=lft[i][j-1]||rgt[i][j]!=rgt[i][j-1]){
flag=false;
}
}
}
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
problem C
$problem$
对一个 \(n \times m\) 的棋盘用黑白相间的方式染色,要求左上角必须是白的,染色次数小于 \(n \times m\)。
无需最小化次数
$solution$
只要保证左上角不要求染上色就行。
考虑从右下角开始,从右到左,从下到上,总能有方式保证当前块涂上色。
时间复杂度: \(O(n \times m)\)
$code$
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=110;
int T,n,sum,m,lft[N][N],rgt[N][N],up[N][N];int a[N][N],flag;string s;
struct aa{int a,b,c,d;}ans[N*N];
signed main(){
// freopen("C.in","r",stdin);
// freopen("C.out","w",stdout);
std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>T;
while(T--){
cin>>n>>m;flag=true;sum=0;memset(ans,0,sizeof(ans));
for(int i=1;i<=n;i++){
cin>>s;
for(int j=1;j<=m;j++){
a[i][j]=(s[j-1]-'0');
}
}if(a[1][1]){cout<<-1<<endl;continue;}
for(int i=n;i>=1;i--){
for(int j=m;j>=1;j--){
if(a[i][j]){
sum++;
if(j==1){
ans[sum].a=i-1;ans[sum].c=i;ans[sum].b=j;ans[sum].d=j;
}else{
ans[sum].a=i;ans[sum].c=i;ans[sum].b=j-1;ans[sum].d=j;
}
}
}
}cout<<sum<<endl;
for(int i=1;i<=sum;i++) cout<<ans[i].a<<" "<<ans[i].b<<" "<<ans[i].c<<" "<<ans[i].d<<endl;
}return 0;
}
problem D
$problem$
给定 $x,d$($2\le x,d\le 10^9$),定义 $d$ 的倍数为“好数”,不能分解为好数之积的好数为“漂亮数”。保证 \(x\) 是好数,询问 \(x\) 是否有两种方式分解为漂亮数之积。