A.Little Artem
题意:
n
∗
m
的
网
格
中
,
有
黑
白
两
种
颜
色
n*m的网格中,有黑白两种颜色
n∗m的网格中,有黑白两种颜色
B
是
相
邻
了
白
色
的
黑
格
数
量
B是相邻了白色的黑格数量
B是相邻了白色的黑格数量
W
是
相
邻
了
黑
色
的
白
格
数
量
W是相邻了黑色的白格数量
W是相邻了黑色的白格数量
构
造
一
个
n
∗
m
的
图
,
保
证
B
=
W
+
1
构造一个n*m的图,保证B=W+1
构造一个n∗m的图,保证B=W+1
题解:
因
为
B
=
W
+
1
,
所
以
让
黑
白
有
x
个
相
邻
的
因为B=W+1,所以让黑白有x个相邻的
因为B=W+1,所以让黑白有x个相邻的
然
后
由
于
黑
色
的
比
白
色
多
,
让
两
个
黑
色
的
相
邻
一
个
公
共
的
然后由于黑色的比白色多,让两个黑色的相邻一个公共的
然后由于黑色的比白色多,让两个黑色的相邻一个公共的
所
以
就
可
以
构
造
出
,
第
一
列
和
第
n
行
全
是
B
,
其
他
是
W
所以就可以构造出,第一列和第n行全是B,其他是W
所以就可以构造出,第一列和第n行全是B,其他是W
这
样
,
每
个
黑
色
对
应
一
个
白
色
这样,每个黑色对应一个白色
这样,每个黑色对应一个白色
但
是
第
一
列
第
n
−
1
行
的
和
第
n
行
第
2
列
的
公
用
一
个
白
色
但是第一列第n-1行的和第n行第2列的公用一个白色
但是第一列第n−1行的和第n行第2列的公用一个白色
所
以
白
色
的
少
一
个
,
保
证
了
B
=
W
+
1
所以白色的少一个,保证了B=W+1
所以白色的少一个,保证了B=W+1
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
for(int i=1;i<n;i++,cout<<endl)
for(int j=1;j<=m;j++)
if(j==1)cout<<'B';
else cout<<'W';
for(int i=1;i<=m;i++)
cout<<'B';
cout<<endl;
}
return 0;
}
B.Kind Anton
题意:
给
定
一
个
长
度
为
n
的
数
组
a
和
数
组
b
给定一个长度为n的数组a和数组b
给定一个长度为n的数组a和数组b
a
的
每
个
元
素
由
{
0
,
1
,
−
1
}
组
成
a的每个元素由\{0,1,-1\}组成
a的每个元素由{0,1,−1}组成
可
以
进
行
一
个
操
作
任
意
次
:
可以进行一个操作任意次:
可以进行一个操作任意次:
对
于
i
<
j
,
a
j
+
=
a
i
对于i<j,a_j+=a_i
对于i<j,aj+=ai
问
a
是
否
能
够
等
于
b
问a是否能够等于b
问a是否能够等于b
题解:
由
于
只
有
前
面
的
数
给
后
面
的
数
赋
值
由于只有前面的数给后面的数赋值
由于只有前面的数给后面的数赋值
所
以
用
m
a
p
或
者
数
组
维
护
已
经
出
现
过
的
1
或
者
−
1
所以用map或者数组维护已经出现过的1或者-1
所以用map或者数组维护已经出现过的1或者−1
所
以
只
需
要
看
如
果
a
i
!
=
b
i
a
i
变
成
b
i
需
要
1
还
是
−
1
所以只需要看如果a_i!=b_i~~~a_i变成b_i需要1还是-1
所以只需要看如果ai!=bi ai变成bi需要1还是−1
如
果
对
于
所
有
i
需
要
的
都
存
在
那
么
就
能
够
等
于
数
组
b
如果对于所有i需要的都存在那么就能够等于数组b
如果对于所有i需要的都存在那么就能够等于数组b
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int a[maxn],b[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
map<int,int> m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
bool f=0;
for(int i=1;i<=n;i++){
if(a[i]==b[i]){m[a[i]]++;continue;}
int d=b[i]-a[i];
if(d>0&&m[1]){m[a[i]]++;continue;}
if(d<0&&m[-1]){m[a[i]]++;continue;}
f=1;m[a[i]]++;
}
if(f)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
return 0;
}
C.Eugene and an array
题意:
给
一
个
长
度
为
n
的
数
组
给一个长度为n的数组
给一个长度为n的数组
问
能
找
到
多
少
个
子
段
,
这
个
子
段
的
任
意
子
段
和
不
为
0
问能找到多少个子段,这个子段的任意子段和不为0
问能找到多少个子段,这个子段的任意子段和不为0
题解:
对
于
每
个
位
置
的
值
,
看
它
能
和
它
前
面
的
多
少
位
可
以
组
成
符
合
条
件
的
子
段
对于每个位置的值,看它能和它前面的多少位可以组成符合条件的子段
对于每个位置的值,看它能和它前面的多少位可以组成符合条件的子段
所
以
要
用
m
a
p
维
护
已
经
枚
举
过
的
前
缀
和
的
最
后
一
次
出
现
位
置
所以要用map维护已经枚举过的前缀和的最后一次出现位置
所以要用map维护已经枚举过的前缀和的最后一次出现位置
然
后
如
果
某
个
前
缀
和
出
现
过
,
说
明
这
次
和
m
a
p
维
护
的
位
置
之
间
和
是
0
然后如果某个前缀和出现过,说明这次和map维护的位置之间和是0
然后如果某个前缀和出现过,说明这次和map维护的位置之间和是0
所
以
只
能
从
m
a
p
的
位
置
的
下
一
个
开
始
到
这
个
点
的
子
段
符
合
所以只能从map的位置的下一个开始到这个点的子段符合
所以只能从map的位置的下一个开始到这个点的子段符合
由
于
子
段
和
不
能
为
0
,
所
以
这
一
段
也
不
能
出
现
在
后
面
的
子
段
中
由于子段和不能为0,所以这一段也不能出现在后面的子段中
由于子段和不能为0,所以这一段也不能出现在后面的子段中
所
以
每
次
更
新
一
个
能
取
到
最
左
值
l
,
就
是
每
次
m
a
p
位
置
的
后
一
个
位
置
所以每次更新一个能取到最左值l,就是每次map位置的后一个位置
所以每次更新一个能取到最左值l,就是每次map位置的后一个位置
如
果
a
i
为
0
,
那
说
明
1
到
i
的
所
有
都
不
能
和
i
后
面
的
形
成
符
合
条
件
的
子
段
如果a_i为0,那说明1到i的所有都不能和i后面的形成符合条件的子段
如果ai为0,那说明1到i的所有都不能和i后面的形成符合条件的子段
所
以
直
接
更
新
最
左
值
l
=
i
+
1
所以直接更新最左值l=i+1
所以直接更新最左值l=i+1
对
于
每
次
位
置
的
更
新
,
答
案
也
加
上
能
取
到
的
结
果
对于每次位置的更新,答案也加上能取到的结果
对于每次位置的更新,答案也加上能取到的结果
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll a[maxn],sum[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],sum[i]=sum[i-1]+a[i];
map<ll,int> m;
int l=0;
ll ans=0;
for(ll i=1;i<=n;i++){
if(!m[sum[i]]&&sum[i]&&a[i])ans+=(i-l);
else if(!a[i])l=i;
else l=max(l,m[sum[i]]+1),ans+=(i-l);
m[sum[i]]=i;
}
cout<<ans;
return 0;
}
D.Challenges in school №41
题意:
一
个
队
列
有
n
个
人
,
每
个
人
站
的
方
向
可
能
是
L
或
R
一个队列有n个人,每个人站的方向可能是L或R
一个队列有n个人,每个人站的方向可能是L或R
可
能
两
个
人
会
有
面
对
面
的
情
况
可能两个人会有面对面的情况
可能两个人会有面对面的情况
你
每
次
至
少
使
一
对
面
对
面
的
人
同
时
转
身
你每次至少使一对面对面的人同时转身
你每次至少使一对面对面的人同时转身
是
否
你
能
够
在
k
次
使
得
这
个
队
列
没
有
面
对
面
的
人
是否你能够在k次使得这个队列没有面对面的人
是否你能够在k次使得这个队列没有面对面的人
如
果
可
以
输
出
这
k
次
翻
转
的
人
如果可以输出这k次翻转的人
如果可以输出这k次翻转的人
题解:
由
于
你
想
让
所
有
面
对
面
的
人
都
不
面
对
面
由于你想让所有面对面的人都不面对面
由于你想让所有面对面的人都不面对面
只
有
每
次
让
他
们
转
身
只有每次让他们转身
只有每次让他们转身
所
以
只
有
暴
力
模
拟
,
直
到
不
出
现
面
对
面
,
每
次
记
录
所以只有暴力模拟,直到不出现面对面,每次记录
所以只有暴力模拟,直到不出现面对面,每次记录
由
于
每
次
至
少
翻
转
一
对
,
所
以
可
以
同
时
翻
转
多
对
面
对
面
的
人
由于每次至少翻转一对,所以可以同时翻转多对面对面的人
由于每次至少翻转一对,所以可以同时翻转多对面对面的人
为
了
使
答
案
最
小
化
,
每
次
翻
转
所
有
面
对
面
的
人
为了使答案最小化,每次翻转所有面对面的人
为了使答案最小化,每次翻转所有面对面的人
如
果
这
样
翻
转
还
是
需
要
比
k
次
数
多
,
说
明
不
可
能
完
成
如果这样翻转还是需要比k次数多,说明不可能完成
如果这样翻转还是需要比k次数多,说明不可能完成
然
而
,
你
可
以
每
次
只
翻
转
一
对
,
可
以
达
到
将
一
次
翻
转
分
成
多
次
的
效
果
然而,你可以每次只翻转一对,可以达到将一次翻转分成多次的效果
然而,你可以每次只翻转一对,可以达到将一次翻转分成多次的效果
但
是
,
如
果
按
这
样
全
部
分
开
,
还
是
比
k
小
,
那
就
说
明
不
能
完
成
但是,如果按这样全部分开,还是比k小,那就说明不能完成
但是,如果按这样全部分开,还是比k小,那就说明不能完成
然
后
,
就
是
按
这
样
,
把
所
有
的
次
数
转
化
成
k
次
完
成
即
可
然后,就是按这样,把所有的次数转化成k次完成即可
然后,就是按这样,把所有的次数转化成k次完成即可
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=3e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
vector<int> v[100010];
vector<int> ans[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,k;
cin>>n>>k;
string s;
cin>>s;
int cnt=0,tot=0;
while(1){
cnt++;
bool f=0;
for(int i=0;i<n;i++)
if(s[i]=='R'&&s[i+1]=='L')
v[cnt].pb(i+1),swap(s[i],s[i+1]),f=1,tot++,i++;
if(!f)break;
if(cnt>k){cout<<-1;return 0;}
}
if(k>tot){cout<<-1;return 0;}
int c=0;
for(int i=1;i<cnt;i++){
for(auto j:v[i]){
if(cnt-i<k)ans[c++].pb(j),k--;
else ans[c].pb(j);
}
if(cnt-i>=k&&!ans[c].empty())c++,k--;
}
for(int i=0;i<c;i++){
cout<<(int)ans[i].size()<<' ';
for(auto j:ans[i])cout<<j<<' ';
cout<<endl;
}
return 0;
}
F.Kate and imperfection
题意:
给
一
个
数
n
给一个数n
给一个数n
让
你
从
1
−
n
中
每
次
找
出
x
个
数
(
2
<
=
x
<
=
n
)
为
集
合
s
让你从1-n中每次找出x个数(2<=x<=n)为集合s
让你从1−n中每次找出x个数(2<=x<=n)为集合s
F
(
s
)
表
示
x
个
数
中
任
意
两
个
数
a
,
b
的
g
c
d
(
a
,
b
)
的
最
大
值
F(s)表示x个数中任意两个数a,b的gcd(a,b)的最大值
F(s)表示x个数中任意两个数a,b的gcd(a,b)的最大值
让
你
使
这
个
对
于
2
<
=
x
<
=
n
使
得
F
(
s
)
最
小
让你使这个对于2<=x<=n使得F(s)最小
让你使这个对于2<=x<=n使得F(s)最小
对
于
x
从
2
−
n
求
出
这
个
最
小
的
F
(
s
)
对于x从2-n求出这个最小的F(s)
对于x从2−n求出这个最小的F(s)
题解:
首
先
自
己
手
写
枚
举
一
下
,
可
以
发
现
首先自己手写枚举一下,可以发现
首先自己手写枚举一下,可以发现
每
次
先
把
质
数
找
齐
,
肯
定
这
些
值
都
是
1
每次先把质数找齐,肯定这些值都是1
每次先把质数找齐,肯定这些值都是1
然
后
再
找
2
,
4
,
6
,
9
,
8
,
10
这
样
的
顺
序
然后再找2,4,6,9,8,10这样的顺序
然后再找2,4,6,9,8,10这样的顺序
而
且
F
(
s
)
是
随
x
递
增
的
而且F(s)是随x递增的
而且F(s)是随x递增的
这
样
会
发
现
,
如
果
一
个
数
不
是
质
数
,
你
又
必
须
选
到
这
个
数
这样会发现,如果一个数不是质数,你又必须选到这个数
这样会发现,如果一个数不是质数,你又必须选到这个数
那
么
F
(
s
)
就
是
这
个
数
的
最
大
因
子
那么F(s)就是这个数的最大因子
那么F(s)就是这个数的最大因子
所
以
问
题
转
化
成
了
,
找
每
个
数
的
最
大
因
子
,
统
计
到
一
起
所以问题转化成了,找每个数的最大因子,统计到一起
所以问题转化成了,找每个数的最大因子,统计到一起
然
后
从
小
到
大
输
出
就
可
以
了
然后从小到大输出就可以了
然后从小到大输出就可以了
这
里
就
可
以
用
类
似
素
数
筛
的
方
法
进
行
预
处
理
这里就可以用类似素数筛的方法进行预处理
这里就可以用类似素数筛的方法进行预处理
然
后
找
到
每
个
数
的
最
大
因
子
,
再
用
v
e
c
t
o
r
读
取
一
遍
排
个
序
然后找到每个数的最大因子,再用vector读取一遍排个序
然后找到每个数的最大因子,再用vector读取一遍排个序
AC代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=5e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
cin>>n;
for(int i=2;i<=n;i++)
if(!a[i])
for(int j=i;j<=n;j+=i)
if(!a[j])a[j]=j/i;
a[1]=1;
vector<int> v;
for(int i=1;i<=n;i++)
if(a[i])v.pb(a[i]);
sort(all(v));
for(int i=1;i<n;i++)
cout<<v[i]<<' ';
return 0;
}