『CF题解』Codeforces Round #632 (Div. 2)【A】【B】【C】【D】【F】

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]

我们记 f i f_i 表示 以 i 结尾的合法段的个数,那么我们要求的就是 i = 1 i = n f i \sum_{i=1}^{i=n}f_i ,我们考虑依次求出每一个 f i f_i

我们这次要求的段的右端点显然都是 i,左端点可以是 [1, i]中的每一个值。那么哪些左端点是合法的呢?显然这是一个后缀,也就是说,如果左端点是 p的时候已经不合法了,那么左端点是 q(q<p)的时候显然是不合法的,因为后者包含了 前者所包含的全部子段

那么我们只要求出最小的合法的位置 p,就知道 f i = i p + 1 f_i = i - p + 1 (即 [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。

显然,我们可以加入 4 = 2 × 2 6 = 2 × 3 , 8 = 2 × 4 , 4=2\times 2,但不可以加入 6=2\times 3,8=2\times 4,\cdots

然后我们考虑使得最大值为 3,那么我们可以加入 6 = 2 × 3 , 9 = 3 × 3 6=2\times 3,9=3\times 3 ,但不能加入 12 = 4 × 3 , 12=4\times 3,\cdots

接下来考虑使得最大值为 4,我们可以加入 8 = 2 × 4 8=2\times 4 ,可是我们不能加入 12 = 3 × 4 12=3\times 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]<<" ";
}
发布了8 篇原创文章 · 获赞 4 · 访问量 1532

猜你喜欢

转载自blog.csdn.net/wxd1233/article/details/105435075