• Codeforces Round #632 (Div. 2)


    Codeforces Round #632 (Div. 2)

    CF1333A Little Artem

    知识点:

    构造

    题意:

    多次询问一个(n imes m)的网格,每个格子填(0,1),要求有(0)相邻的(1)的个数是有(1)相邻的(0)的个数(+1),求一种方案。

    解法:

    因为(n)(m)都不小于(2),所以直接构造第一行第一列是(0),其他是(1)即可。

    备注:

    #include<bits/stdc++.h>
    using namespace std;
    
    int T,n,m;
    
    int main()
    {
    	int i,j;
    	cin>>T;
    	while (T--)
    	{
    		cin>>n>>m;
    		for (i=1;i<=n;i++)
    		{
    			for (j=1;j<=m;j++)
    			{
    				if (i==1&&j==1)
    					putchar('W');
    				else
    					putchar('B');
    			}
    			puts("");
    		}
    	}
    }
    

    CF1333B Kind Anton

    知识点:

    模拟

    题意:

    给定两个序列,第一个序列的数是({-1,0,1})中的数。一个序列可以操作无限次,每次操作选定不同的两个数((i,j)),要求(ileq j , a_j=a_i+a_j),问第一个序列是否能变成第二个,多次询问。

    解法:

    因为后面的数不会对前面产生贡献,所以从后往前模拟一遍,用两个计数器分别记录当前点前面的(-1,1)的个数,然后看差值的正负判断即可。

    备注:

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100010;
    int T,n,a[maxn],b[maxn],c[5],ans;
    
    int main()
    {
    	int i;
    	cin>>T;
    	while (T--)
    	{
    		cin>>n;
    		memset(c,0,sizeof(c));
    		for (i=1;i<=n;i++)
    		{
    			cin>>a[i];
    			c[a[i]+1]++;
    		}
    		for (i=1;i<=n;i++)
    			cin>>b[i];
    		ans=1;
    		for (i=n;i>=1;i--)
    		{
    			c[a[i]+1]--;
    			if (a[i]==b[i])
    				continue;
    			int d=b[i]-a[i];
    			if (d>0)
    			{
    				if (c[2]<=0)
    				{
    					ans=0;
    					break;
    			}
    			}
    			if (d<0)
    			{
    				if (c[0]<=0)
    				{
    					ans=0;
    					break;
    				}
    			}
    		}
    		puts(ans?"YES":"NO");
    	}
    }
    

    CF1333C Eugene and an array

    知识点:

    计数,前缀和,双指针

    题意:

    给定一个序列,定义一个序列是好的为这个序列的所有非空子串都不为(0)。问一个序列的所有子串中是好的有多少个。

    解法:

    经过多次尝试(本来我想用一种在(ABC)中见过的方法,就是统计不合法的有多少个,但是发现这样去不了重,所以不行),发现肯定是
    先求前缀和,假如一个子串是好的,那一定是这个子串中不会出现前缀和相等的数而且当前右端点的(a_i)不为(0)。发现这个东西是有单调性的,所以用(map)维护每个前缀和出现的次数,然后两个指针维护当前的合法区间,是线性的。

    备注:

    这道题我还(WA)了两次,要特别注意当前点的(a_i)(0)的情况,这种情况直接特判不算进答案里。但是右移指针的方法没变,还是找到第一个令当前前缀和次数为(1)为止。因为这个区间是前缀和区间,假如(l=r)那么就没有东西了。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int maxn=200010;
    int n,a[maxn];
    ll ans,s[maxn];
    map<ll,int>mp;
    #define mkp make_pair
    
    int main()
    {
    	int i,l,r;
    	scanf("%d",&n);
    	for (i=1;i<=n;i++)
    		scanf("%d",&a[i]),s[i]=s[i-1]+a[i];
    	if (n==1)
    	{
    		if (a[1]==0)
    			puts("0");
    		else
    			puts("1");
    		return 0;
    	}
    	l=0;
    	mp.insert(mkp(0,1));
    	for (r=1;r<=n;r++)
    	{
    		if (mp.find(s[r])==mp.end())
    			mp.insert(mkp(s[r],1));
    		else
    			mp[s[r]]++;
    		/*if (a[r]==0)
    		{
    			while (l<=r)
    			{
    				mp[s[l]]--;
    				l++;
    			}
    			continue;
    		}*/
    		while (mp[s[r]]==2&&l<=r)
    		{
    			mp[s[l]]--;
    			l++;
    		}
    		if (a[r]!=0)
    			ans+=r-l;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    CF1333D Challenges in school №41

    知识点:

    贪心,逆序对,冒泡排序

    题意:

    有一个序列,每个位置要么往左看要么往右看,现在每一秒可以让至少一对盯着对方的人同时转头,但是同一秒一个人只能转一次。问恰
    (k)步使得没有人互相盯着的一种方案。

    解法:

    显然,在最后肯定是左边一段的人全都看着左边,右边剩下的人都看着右边才能满足条件。于是我们让(L)(0)(R)(1)。我们进行一轮冒泡排序,可以让若干对盯着对方的人(也就是逆序对)交换,而且可以发现这些人肯定是不会重复的,而且是这轮中能选的最多的了。然后交换,冒泡直到没有逆序对为止。那么答案的下界就是冒泡的次数,上界就是冒泡影响过的位置的总次数(每一次交换我们都拆开来算一次)。假如答案不在这个区间内,那就无解。否则肯定有解。然后用调整法,让前面若干轮直接冒泡,后面的拆开来一次次地冒泡即可。

    备注:

    可以先求一个冒泡的前缀和,方便后面统计,而且这道题细节很繁琐。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=3010;
    int n,k,a[maxn],s[maxn],minv,maxv;
    vector<int>v[maxn];
    char c[maxn];
    #define pb push_back
    
    int main()
    {
    	int i,j,cnt,cur;
    	scanf("%d%d%s",&n,&k,c+1);
    	for (i=1;i<=n;i++)
    		a[i]=(c[i]=='R');
    	for (i=1;i<=n;i++)
    	{
    		cnt=0;
    		for (j=1;j<n;j++)
    			if (a[j]>a[j+1])
    			{
    				++cnt;
    				v[i].pb(j);
    			}
    		maxv+=cnt;
    		s[i]=maxv;
    		if (!cnt)
    		{
    			minv=i-1;
    			break;
    		}
    		for (j=0;j<cnt;j++)
    			swap(a[v[i][j]],a[v[i][j]+1]);
    	}
    	if (k<minv||k>maxv)
    	{
    		puts("-1");
    		return 0;
    	}
    	if (k==minv)
    	{
    		for (i=1;i<=minv;i++)
    		{
    			cnt=v[i].size();
    			printf("%d ",cnt);
    			for (j=0;j<cnt;j++)
    				printf("%d ",v[i][j]);
    			puts("");
    		}
    		return 0;
    	}
    	cur=0;
    	while (cur<minv&&maxv-s[cur+1]+cur+1>=k)
    		cur++;
    	for (i=1;i<=cur;i++)
    	{
    		cnt=v[i].size();
    		printf("%d ",cnt);
    		for (j=0;j<cnt;j++)
    			printf("%d ",v[i][j]);
    		puts("");
    	}
    	if (maxv-s[cur]+cur-k+1>0)
    	{
    		cnt=maxv-s[cur]+cur-k+1;
    		printf("%d ",cnt);
    		for (j=0;j<cnt;j++)
    			printf("%d ",v[cur+1][j]);
    		puts("");
    	}
    	cnt=v[cur+1].size();
    	for (j=maxv-s[cur]+cur-k+1;j<cnt;j++)
    		printf("1 %d
    ",v[cur+1][j]);
    	for (i=cur+2;i<=minv;i++)
    	{
    		cnt=v[i].size();
    		for (j=0;j<cnt;j++)
    			printf("1 %d
    ",v[i][j]);
    	}
    	return 0;
    }
    

    CF1333E Road to 1600

    知识点:

    构造

    题意:

    解法:

    不会

    备注:

    CF1333F Kate and imperfection

    知识点:

    数学,(GCD),线性筛

    题意:

    给定一个(n),一个集合里有不超过(n)的所有正整数。要求对于每一个(2)(n)(k),所有大小为(k)的集合中,对于每个集合,两两求出(GCD),每个集合的贡献是最大的(GCD),而对于每个(k)的答案是当前所有集合中的贡献值的最小值。求出所有的贡献最小值。

    解法:

    首先可以观察到一个性质,假如一个数(x)要加入当前某个集合,那么它所有的真因子都肯定在里面。原因是假如不在的话肯定假如那些
    真因子更优。而假如之后这个数产生的贡献(GCD)最大值肯定是(x)的最大真因子。有因为能加入(x)了,答案肯定不会变小,所以答案肯
    定就是这个最大真因子。而最大真因子等于(x)除以最小质因子,也就是线性筛中筛到的第一个质数对应的(i),那么那这个来排个序然
    后从小到大加入数就是答案了。

    备注:

    注意:1,线性筛中的(i)是否是当前质数的倍数这个要放在处理完因数之后。2,质数个数最好开(n)这么大,否则有可能(RE)

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=500010;
    int n,m,pr[maxn],mc[maxn];
    bool v[maxn];
    
    int main()
    {
    	int i,j;
    	cin>>n;
    	for (i=2;i<=n;i++)
    	{
    		if (!v[i])
    		{
    			pr[++m]=i;
    			mc[i]=1;
    		}
    		for (j=1;j<=m&&pr[j]*i<=n;j++)
    		{
    			v[pr[j]*i]=1;
    			mc[pr[j]*i]=i;
    			if (i%pr[j]==0)
    				break;
    		}
    	}
    	sort(mc+2,mc+n+1);
    	for (i=2;i<=n;i++)
    		printf("%d ",mc[i]);
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    C# 开发(创蓝253)手机短信验证码接口
    33条C#、.Net经典面试题目及答案
    请用一句sql语句取出各科的平均成绩,显示字段,科目,平均成绩
    写出一条Sql语句:取出表A中第31到第40记录(SQLServer,以自动增长的ID作为主键,注意:ID可能不是连续的。
    SQL的四种连接-左外连接、右外连接、内连接、全连接
    C# 获取mp3文件的歌曲时间长度
    欧拉公式
    linux环境java入门
    C内存分配
    机器学习网址归纳
  • 原文地址:https://www.cnblogs.com/Ronald-MOK1426/p/12669431.html
Copyright © 2020-2023  润新知