A. Little Artem
本题的题意大致为给你一个nxm大小的矩阵,要求你将其中的格子涂成白色或者黑色,定义一个白色格子周围如果有至少一个黑色的格子,那么这个白色的格子为好格子,黑色格子亦是如此,要求黑色好格子的数量为白色好格子数量+1。
这题乍一看好像很难,但是题目有 2<=n,m,这就意味着,我们总是可以构造出一个矩阵,其一个角落涂成白色,其它的都涂成黑色。不难证明,因为只有2个黑格子与角落的白格子相邻,所以永远满足。
主要代码:
int t;cin>>t;
while(t--){
int n,m;cin>>n>>m;
int fi =1;
for(int i = 0;i < n;++i){
for(int j = 0;j < m;++j){
if(fi){cout<<'W';fi=0;}//仅最左上角涂白,其它全为黑
else cout<<'B';
}
cout<<'\n';
}
}
B. Kind Anton
本题的题意大致为给你一个长为n的数组a,a中的元素只有{0,1,-1},可以进行如下操作0或者多次:
1、取a数组两个数 a i a_{i} ai, a j a_{j} aj(0<=i<j<n),
2、 a j a_{j} aj= a i a_{i} ai+ a j a_{j} aj
问是否能得到目标数组b。
因为 i<j,那就不难想到,当
b
i
b_{i}
bi<
a
i
a_{i}
ai,只要判断
a
i
a_{i}
ai前面有没有-1;当
a
i
a_{i}
ai<
b
i
b_{i}
bi,只要判断
a
i
a_{i}
ai前有没有1;而
a
i
a_{i}
ai=
b
i
b_{i}
bi的时候不用判断。
主要代码:
const int N = 1e5+5;
int a[N],b[N];
int T;cin>>T;
while(T--){
bool flag = true;
bool p1 = false,p2 = false;//分别用于判断这个数前面是否有1,-1
int n;cin>>n;
for(int i = 0;i < n;++i)cin>>a[i];
for(int i = 0;i < n;++i)cin>>b[i];
for(int i = 0;i < n;++i){
if(a[i]<b[i]&&!p1)flag = false;//当a[i]<b[i],并且a[i]前没有1,输出NO
else if(a[i]>b[i]&&!p2)flag = false;//当a[i]>b[i],并且a[i]前没有-1,输出NO
if(a[i]==1)p1 = true;
else if(a[i]==-1)p2 = true;
}
if(flag)cout<<"YES\n";
else cout<<"NO\n";
}
C. Eugene and an array
这题的题意很绕,刚开始都绕晕了,大致意思可以理解为,给你一个长为n的数组,要你求这个数组有多少个好的子数组(连续的),一个好的子数组定义为:这个子数组的所有子数组的各自的元素之和不为0。
那么很明显,既然是要求和,那必然就有区间操作,但这里用线段树硬搞很费时间,用前缀和处理即可,前缀和相同的就不是好的子数组,那么包含这个子数组的子数组也不是好的子数组,那么问题就可以转为求,不包含这些前缀和相同的的下标构成的大区间的区间,我们只需要在遍历的时候不断地更新重复区间的左端点,
∑
1
n
\sum_1^n
∑1n(i - 左端点 -1),即为要求的答案.。统计重复出现的前缀和用map即可,最好不要用unordermap,因为一卡哈希冲突就o(n)寻访了,而CF卡哈希冲突是常事。
主要代码:
const int N = 2e5+5;
int a[N];
map<ll,int>mp;
int n;cin>>n;
mp[0] = 0;//很重要,初始的0的下标即为0
long long qz = 0,ans = 0;
int pos = -1,x;//左端点从-1开始,这样区间数就是下标
for(int i = 0;i <= n;++i){
cin>>x;
qz+=x;
if(mp.count(qz))pos = max(pos,mp[qz]);//更新左端点
ans += i - pos - 1;
mp[qz] = i;
}
cout<<ans<<'\n';
C本人想法就是求区间,如果有更好的想法欢迎留言OWO