完整题解
我总算上橙了。。。。
题目意思
- A
- 给你 的矩阵,只有 和 ,相邻有其他不一样的点叫做好点,还需要让好点 的数量多于 。
- 睿智构造
- 一分钟写完,只要把 涂成 即可
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
int a[111][111],n,m,T;
int main()
{
int T=read();
for (;T--;)
{
n=read();
m=read();
a[1][1]=1;
for ( int i=1;i<=n;i++ )
{
for ( int j=1;j<=m;j++ )
if(a[i][j]) putchar('W');
else putchar('B');
puts("");
}
}
}
题目意思
- B
- 给你一个数组 , 。称一次操作 为: 。问是否能通过若干次操作让他变成
- 首先:我的做法比较麻烦
- 我们先记录原序列 中 的数量。我们重前往后找,如果存在 那么前面一定存在 。如果存在 那么前面一定存在 。于是就直接模拟即可。注意 个数的更新。
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=1e5+5;
int n,m,a[N],b[N];
int main()
{
int T=read();
for (;T--;)
{
n=read();
int s0=0,s1=0,s2=0;
for ( int i=1;i<=n;i++ )
a[i]=read();
for ( int i=1;i<=n;i++ )
{
b[i]=read();
}
for ( int i=1;i<=n;i++ )
{
if(a[i]==b[i])
{
if(a[i]==1) s1++;
if(a[i]==-1) s2++;
continue;
}
if(a[i]<b[i])
{
if(s1)
{
if(b[i]==-1) s2++;
if(b[i]==1) s1++;
}
else
{
printf("NO\n");
goto rp;
}
if(a[i]==-1) s2++;
if(a[i]==1) s1++;
}
if(a[i]>b[i])
{
if(s2)
{
if(b[i]==-1) s2++;
if(b[i]==1) s1++;
}
else
{
printf("NO\n");
goto rp;
}
if(a[i]==-1) s2++;
if(a[i]==1) s1++;
}
}
printf("YES\n");
rp:;
}
}
题目意思
- C
- 给定长度为 的序列,定义序列 为好的,当且仅当: 的子段中不存在 值为0。
- 我是先做了一遍前缀和,再尺取法了一下。
- 也就是:若 在 前面存在,那么这样的序列只能最后一次取到 的下标 以后,数量为 。
#include <bits/stdc++.h>
#define pb push_back
#define int long long
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=2e5+5;
int n,m,a[N],sum[N],l,r,ans;
map<int,int> mp;
signed main()
{
n=read();
for ( int i=1;i<=n;i++ )
{
a[i]=a[i-1]+read();
mp[a[i]]=0;
}
mp[0]++;
mp[a[1]]++;
int l=1,r=1;
while(l<=n)
{
while(r<n&&!mp[a[r+1]]) mp[a[++r]]++;
if(mp[a[l]]<=1)
ans+=r-l+1;
mp[a[l-1]]--;
l++;
}
printf("%lld\n",ans);
return 0;
}
题目意思
- D
- 给你一个含 序列就是称一次操作可以将若干 对翻转,问能否在 次使得序列无法翻转。
-
一道比较 的构造题目
-
我们首先考虑如何使得答案最优,我们是不是只要每次能翻就翻。我们记录这个最少翻转次数为
-
同理,我们再考虑如何使得答案最差,我们是不是只要每次能翻只翻转一个。我们记录这个最大翻转次数为
-
对于无解的情况即: 或者 ,这个很好理解
-
那么这样就简单了,我们只要去凑数字。即如果 ,那么我们就选择最差的方式去反转直到 。对于剩下的我们选择用最优秀的方法翻转即可。这样就可以构造一个合法的答案了。
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=3005;
int n,m,ans,a[N],b[N],tmp[N],mi,mx;
char ch[N];
int main()
{
n=read();
m=read();
scanf("%s",ch+1);
for ( int i=1;i<=n;i++ )
{
a[i]=(ch[i]=='R')?1:-1;
b[i]=a[i];
}
while(1)
{
int flg=0;
for ( int i=1;i<n;i++ )
if(a[i]==1&&a[i+1]==-1)
{
flg=1;
swap(a[i],a[i+1]);
i++;
mx++;
}
if(!flg) break;
mi++;
}
if(m<mi||m>mx) return printf("-1\n"),0;
for ( int i=1;i<=n;i++ ) a[i]=b[i];
while(1)
{
int i=1;
for(;i<n;++i)
{
if(m==mi) break;
if(a[i]==1&&a[i+1]==-1)
{
swap(a[i],a[i+1]);
m--;
printf("%d %d",1,i);
puts("");
i++;
}
}
int gs=0;
for(;i<n;++i)
{
if(a[i]==1&&a[i+1]==-1)
{
swap(a[i],a[i+1]);
tmp[++gs]=i;
i++;
}
}
if(gs)
{
printf("%d ",gs);
for ( int j=1;j<=gs;j++ ) printf("%d ",tmp[j]);
m--;
puts("");
}
mi--;
if(!m) break;
}
return 0;
}
题目意思
-
首先 是无解的
-
对于有解的情况我们考虑皇后先按照车走的方法走(即这时候不会产生贡献)然后我们再强制皇后不优秀的方法走,那么我们有如下的构造方法:
-
我们构造一个 的矩形使得把皇后逼到 那一格,然后这个时候强制让皇后花费 走到 那一格子就可以了。
-
于是车就用微小的优势获胜了。
-
一下构造就很简单了,具体看代码。
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=505;
int n,m,a[N][N],ans;
int main()
{
n=read();
if(n<3) return printf("-1\n"),0;
for ( int i=n;i>3;i-- ) a[1][i]=++m;
for ( int i=4;i<=n;i++ ) a[2][i]=++m;
for ( int i=3;i<n;i++ )
{
if(i&1)
for ( int j=n;j>=1;j-- ) a[i][j]=++m;
else
for ( int j=1;j<=n;j++ ) a[i][j]=++m;
}
if(n&1)
{
for ( int j=n;j>=1;j-- )
if(j!=2) a[n][j]=++m;
}
else
for ( int j=1;j<=n;j++ )
if(j!=2) a[n][j]=++m;
a[n][2]=++m;
a[1][2]=++m,a[2][1]=++m,a[2][2]=++m,a[1][3]=++m,a[2][3]=++m;
a[1][1]=++m;
for ( int i=1;i<=n;i++,puts("") )
for ( int j=1;j<=n;j++ )
printf("%d ",a[i][j]);
return 0;
}
- 做出 第一次啊!这是真的水呀
题目意思
- F
- 给 的连续自然数。对 的每个 ,都枚举所有大小恰好为 的子集,然后定义一个函数 , 参数是一个集合,其遍历集合中所有的二元组,求出二元组的 ,然后取这些 里面的最大值,对每个 求函数 的最小值。
- 首先我们考虑如何最优秀:即先加入所有的质数,再加 的倍数。然后加到一个合数,他所有的因子必定存在于已有的集合(因为是一个一个加上去的 )。那么把每个数的最大因子搞出来,排遍序输出即可。
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
inline int read()
{
int sum=0,ff=1; char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') ff=-1;
ch=getchar();
}
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum*ff;
}
const int N=5e5+5;
int n,tot,cnt[N],vis[N],alb[N],d[N];
vector<int> G[N];
inline void init()
{
vis[1]=d[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])
alb[++tot]=d[i]=i;
for(int j=1;j<=tot && i*alb[j]<=n;j++)
{
vis[i*alb[j]]=1;d[i*alb[j]]=alb[j];
if(i%alb[j]==0)break;
}
}
}
signed main()
{
n=read();
int sum=1,i=1;
init();
for(int i=1;i<=n;i++) vis[i]=0;
for(int i=2;i<=n;i++) d[i]=i/d[i];
sort(d+1,d+n+1);
for(int i=2;i<=n;i++) printf("%d ",d[i]);
return 0;
}