ROUND 209 解题报告
A Table
关键字:构造
思路:
答案相当于是否存在一个边界上的格子值为1,且不是拐角。因为如果我们找到了这样一个点,我们可以将这个点,向对边两个点构成的两个矩形染色,这样就能在2的时间内完成。反之,不难证明,只能在4的时间内完成。
时间复杂度:O(nm)
空间复杂度:O(1)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int num;
int main()
{
cin>>n>>m;
int flag=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int x;
cin>>x;
if ((i!=1||i!=n)&&(j!=1||j!=m)&&x==1)
{
if (i==1||i==n||j==1||j==m) flag=1;
}
}
if (flag) cout<<2<<endl;
else cout<<4<<endl;
return 0;
}
B Permutation
关键字:构造
思路:
我们首先考虑k为0时的情况。只要我们在第一个sigma中的每个绝对值内正负情况相同,就能保证k=0 。这个不难构造,只要按1到2*n的顺序排列即可。考虑其他k的情况,如果k=1,我们交换1 和 2的位置,此时后面式子的值将会减二。如果k=2,那么在k=1的基础上,交换3和4的位置即可。。通过这种方式,我们就可以构造出要求的序列了。
时间复杂度:O(n)
空间复杂度:O(1)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
<span style="white-space: pre;"> </span>int n,k;
<span style="white-space: pre;"> </span>cin>>n>>k;
<span style="white-space: pre;"> </span>for (int i=1;i<=n;i++)
<span style="white-space: pre;"> </span>{
<span style="white-space: pre;"> </span>if (k>0) printf("%d %d",2*i,2*i-1);
<span style="white-space: pre;"> </span>else printf("%d %d",2*i-1,2*i);
<span style="white-space: pre;"> </span>if (i!=n) printf(" ");
<span style="white-space: pre;"> </span>k--;
<span style="white-space: pre;"> </span>}
<span style="white-space: pre;"> </span>printf("\n");
<span style="white-space: pre;"> </span>return 0;
}
C Prime Number
关键字:STL
思路:
类似于进制的加法。我们所要求的结果,就是将ai序列的相同项不断合并,直至不能再合并时,x的(Σai-当前最大ai)次方的值。这里我们用一个map就可以轻松完成。从最大的ai开始往0遍历,如果当前值是x的倍数,那就将当前值除以x的值加到前一项中。直到不满足当前值是x的倍数这个条件时结束。
时间复杂度:O(n)
空间复杂度:O(n)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;
LL pow_mod(LL a,LL i,LL n)
{
if (i==0) return 1%n;
LL temp=pow_mod(a,i>>1,n);
temp=temp*temp%n;
if (i&1) temp=(LL) temp*a%n;
return temp;
}
const LL mod=1e9+7;
LL n,x;
LL a[110000];
map<LL,LL> w;
int main()
{
cin>>n>>x;
LL sum=0;
w.clear();
for (int i=0;i<n;i++)
{
cin>>a[i];
w[a[i]]++;
sum+=a[i];
}
int i=a[n-1];
while (w[i]%x==0)
{
w[i-1]+=w[i]/x;
i--;
}
if (i<0) i=0;
cout<<pow_mod(x,sum-i,mod)<<endl;
return 0;
}
D Pair of Numbers
关键字:暴力
思路:
我们从j=1开始枚举aj的值。然后分别从两边扩展,直到当前数不是aj的倍数为止。这里加一个小优化就可以过:如果当前最右边扩展到r,那么下次j从r+1开始,不影响程序的正确性。
时间复杂度:O(n)
空间复杂度:O(n)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int a[400000],w[400000];
int main()
{
int n;
cin>>n;
for (int i=0;i<n;i++)
cin>>a[i];
int maxx=0,num=0;
for (int i=0;i<n;)
{
int r,l;
r=l=i;
while (l&&a[l-1]%a[i]==0) l--;
while (r<n-1&&a[r+1]%a[i]==0) r++;
i=r+1;
r-=l;
if (r>maxx) num=0,maxx=r;
if (r==maxx) w[num++]=l+1;
}
cout<<num<<" "<<maxx<<endl;
for (int i=0;i<num;i++)
{
cout<<w[i];
if (i!=n) printf(" ");
else printf("\n");
}
return 0;
}
E Neatness
关键字:构造
思路:
题目只要求找出解,并没有要求最短,所以此题主要难点在于构造。我们可以用最“蠢”的方法,但是保证其最大的正确性:dfs。首先需要dfs(x0,y0)。Dfs时,需要判断四个方向,是否有未遍历过且可达的点,我们再递归去遍历该点。另外一个策略就是,每每第一次到一个点时,将其灯打开,最后一次回到这个点时,将灯关闭,这样就保证了策略的正确性。
时间复杂度:O(n^2)
空间复杂度:O(n^2)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
int n,x,y;
int a[600][600],pp[600][600],sum=0;
char q[4000000];
int ans=0;
const int D[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
const char c[4]={'R','L','D','U'};
bool check(int x,int y,int d)
{
for (x+=D[d][0],y+=D[d][1];x>=1&&x<=n&&y>=1&&y<=n;x+=D[d][0],y+=D[d][1])
if (a[x][y]) return !pp[x][y];
return 0;
}
void dfs(int x,int y)
{
pp[x][y]=1;
if (!a[x][y])
{
a[x][y]=1;
sum++;
ans++;
q[ans]='1';
}
for (int i=0;i<4;i++)
if (check(x,y,i))
{
ans++;
q[ans]=c[i];
dfs(x+D[i][0],y+D[i][1]);
ans++;
q[ans]=c[i^1];
}
a[x][y]=0;
sum--;
ans++;
q[ans]='2';
}
int main()
{
cin>>n>>x>>y;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%d",&a[i][j]),sum+=a[i][j];
dfs(x,y);
if (sum)
{
cout<<"NO"<<endl;
return 0;
}
cout<<"YES"<<endl;
for (int i=1;i<=ans;i++)
printf("%c",q[i]);
cout<<endl;
return 0;
}