CF1333A Little Artem【基础】
思路:签到
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(void){
int t;
cin >> t;
while(t--){
int n,m;
cin >> n >> m;
cout<<"W";
for(int i = 1; i <= m-1; i++) cout<<"B";
cout<<endl;
for(int i = 1; i <= n-1; i++){
for(int j = 1; j <= m; j++){
cout<<"B";
}
cout<<endl;
}
}
return 0;
}
CF1333B Kind Anton【基础】
思路:当a>b的时候,判断前面是否出现过-1,当a<b的时候,判断前面是否出现过1即可。PS:我写的比较麻烦,简单代码可以看别人的。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int a[maxn];
int b[maxn];
struct Node{
int x,y;
}node[maxn];
int main(void){
int t;
cin >> t;
while(t--){
int n;
cin >> n;
int cnt1 = 0;
int cnt2 = 0;
for(int i = 1; i <= n; i++){
cin >> a[i];
if(a[i]>0){
node[i].x = ++cnt1;
node[i].y = cnt2;
}
if(a[i]==0){
node[i].x = cnt1;
node[i].y = cnt2;
}
if(a[i]<0){
node[i].x = cnt1;
node[i].y = ++cnt2;
}
// cout<<a[i]<<" "<<node[i].x<<" "<<node[i].y<<endl;
}
bool flag = 0;
for(int i = 1; i <= n; i++) cin >> b[i];
for(int i = n; i >= 1; i--){
// cout<<a[i]<<" "<<node[i].x<<" "<<node[i].y<<endl;
if(a[i]>b[i]){
if(node[i-1].y==0){
flag = 1;
cout<<"NO"<<endl;
break;
}
}
if(a[i]<b[i]){
if(node[i-1].x==0){
flag = 1;
cout<<"NO"<<endl;
break;
}
}
}
if(flag==0){
cout<<"YES"<<endl;
}
}
return 0;
}
CF1333C Eugene and an array【前缀和】
思路:首先要知道如果一段区间[l,r]的前缀和为0,那么sum[l-1]=sum[r]。
我们记 表示 以 i 结尾的合法段的个数,那么我们要求的就是 ,我们考虑依次求出每一个 。
我们这次要求的段的右端点显然都是 i,左端点可以是 [1, i]中的每一个值。那么哪些左端点是合法的呢?显然这是一个后缀,也就是说,如果左端点是 p的时候已经不合法了,那么左端点是 q(q<p)的时候显然是不合法的,因为后者包含了 前者所包含的全部子段。
那么我们只要求出最小的合法的位置 p,就知道 (即 [p, i] 中的位置的个数)。我们知道 i以前可能会有若干个和为 0 的段,那么,p就是这些段的 左端点的最大值 +1,因为当 p小于等于这个左端点的最大值时,这个含有最大左端点的 0 段就一定被完整包含了。
具体看代码
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
ll a[maxn];
map<ll,ll> mp;
int main(void){
int n;
cin >> n;
for(int i = 1; i <= n; i++){
cin >> a[i];
a[i] += a[i-1];
}
mp[0] = 0;
ll maxl = 0;
ll ans = 0;
for(int i = 1; i <= n; i++){
if(mp.count(a[i])) maxl = max(maxl,mp[a[i]]+1);
ans += i-maxl;
mp[a[i]] = i;
}
cout<<ans<<endl;
return 0;
}
CF1333D Challenges in school №41【构造】
思路:最好的情况是每一趟的过程中,碰到RL就交换。
最坏的情况是每次交换一个RL。
我们记前者为minn,后者为maxx。
显然不存在的情况就是minn<k或者k>maxx。
如果minn<=k<=maxx,我们可以构造出任何一种解。
在k>minn之前,每次只输出一个,k=minn之后,每次输出一趟。
PS:一道好想不好写的代码,可能 是我太菜(自信点,把可能去掉)
对了,这道题卡cin,cout。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3005;
int n,k,ans,a[maxn],b[maxn],tmp[maxn],minn,maxx;
int main(void)
{
cin >> n >> k;
for(int i = 1;i <= n;i++)
{
char ch;
cin >> ch;
a[i] = (ch=='R')?1:0;
b[i] = a[i];
}
while(1)
{
int flag = 0;
for (int i = 1; i < n; i++)
if(a[i]==1&&a[i+1]==0)
{
flag = 1;
swap(a[i],a[i+1]);
i++;
maxx++;
}
if(!flag) break;
minn++;
}
if(k < minn||k > maxx){
cout<<-1<<endl;
return 0;
}
while(1)
{
int i = 1;
for(;i < n; i++)
{
if(k==minn) break;
if(b[i]==1&&b[i+1]==0)
{
swap(b[i],b[i+1]);
k--;
printf("%d %d",1,i);
puts("");
i++;
}
}
int cnt = 0;
for(; i < n; i++)
{
if(b[i]==1&&b[i+1]==0)
{
swap(b[i],b[i+1]);
tmp[++cnt] = i;
i++;
}
}
if(cnt)
{
printf("%d ",cnt);
for (int j = 1; j <= cnt; j++) printf("%d ",tmp[j]);
k--;
puts("");
}
minn--;
if(!k) break;
}
return 0;
}
CF1333F Kate and imperfection【数论-因数分解】
思路:显然要求的结果是单增的。
开始时集合大小为 1,我们强制集合中只包含 1。我们贪心地往集合内加入元素。
由于我们需要使集合中两两 gcd 的最大值最小,一开始我们一定是考虑依次加入所有质数。
加入完所有质数后,我们不可能再保证答案为 1,我们考虑放宽限制,使得两两 gcd 的最大值为 2。
显然,我们可以加入
然后我们考虑使得最大值为 3,那么我们可以加入 ,但不能加入
接下来考虑使得最大值为 4,我们可以加入 ,可是我们不能加入 ,因为之前已经加入了 6。
那么什么时候可以加入 12?在我们枚举最大值为 6 时才可以加入 12。
再往后模拟若干次,大胆猜想,一个数 x会在枚举最大值为 x 的最大真因子(即不等于本身的因子)时被加入集合。
因此,我们可以在调和级数时间内求出每个数的最大真因子,然后排序从小到大输出即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
int n,b[maxn];
int main(void){
int n;
cin >> n;
for(int i = 1; i <= n; i++){
for(int j = i+i; j <= n; j+=i)
b[j] = i;
}
// for(int i = 2; i <= n; i++) cout<<b[i]<<" ";
cout<<endl;
sort(b+1,b+n+1);
for(int i = 2; i <= n; i++) cout<<b[i]<<" ";
}