牛客周赛round7题解

牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

A题:直接模拟就可以了,用cnty,cnto,cntu记录字符的个数,判断每一个2*2的小矩阵里面如果

cnty,cntu,cnto都大于0的话就把答案++

#include
using namespace std;
typedef long long ll;
const int N=310;
int vis[1001][1001];
int pos[N];
int a[N];
int cnty,cntu,cnto;
char w[1001][1001];
void cf()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			char c;
			cin>>c;
			w[i][j]=c;
		}
	}
	
	int p=0;
	for(int i=1;i<=n-1;i++)
	{
		for(int j=1;j<=m-1;j++)
		{
			 cnty=0;
			 cntu=0;
			 cnto=0;
			if(w[i][j]=='y')cnty++;
			else if(w[i][j]=='u')cntu++;
			else if(w[i][j]=='o')cnto++;
			if(w[i][j+1]=='y')cnty++;
			else if(w[i][j+1]=='u')cntu++;
			else if(w[i][j+1]=='o')cnto++;
			if(w[i+1][j]=='y')cnty++;
			else if(w[i+1][j]=='u')cntu++;
			else if(w[i+1][j]=='o')cnto++;
			if(w[i+1][j+1]=='y')cnty++;
			else if(w[i+1][j+1]=='u')cntu++;
			else if(w[i+1][j+1]=='o')cnto++;
			if(cnty>0&&cntu>0&&cnto>0)p++; 
			
		}
	}
	cout<

B题这种01串的题目挺常见的

因为最后相连的字符都不同所以就是说肯定是01010101这样

所以我们把长度为n的字符分别构造出两种:010101...和1010101...这样然后分别计算把原字符串改成这两串的代价,取两个的min就可以

#include
using namespace std;
typedef long long ll;
const int N=310;
int vis[1001][1001];
int pos[N];
int a[N];
int cnty,cntu,cnto;
char w[1001][1001];
void cf()
{
	int n;
	string s;
	cin>>s;
	n=s.size();
	string s1,s2;
	for(int i=0;i

C题:因为区间范围是l-r最大的话肯定尽量都是l

所以答案就是max=(b-a)/l

min=(b-a+r-1)/r//这里加r-1是上取整操作,如果说mod r还有余数的话我们就去再加一个数而不是把倒一的数去取比r小的数,因为这里要操作数最大,所以我们尽量去多加数

至于max的话l也可能不会整除但是我们可以倒一个数不取l取l+(b-a)%l这样答案就还是(b-a)/l

这里大家可能会问了,那如果余数不够呢

我们知道mod l的余数最大是l-1

如果说区间(r-l)小于l-1的话那说明((b-a)/l和(b-a)/ r)这两个的结果是一样的,在有余数的情况下((b-a)+r-1)/r由于上取整最后的答案是会比(b-a)/l大的也就是说min>max这是不可能的,这种情况下我们就无法得到答案,那就是-1,也就是说min>max这个条件是看余数是不是会比区间大,也就可以解决我们余数判断的疑惑了

#include
using namespace std;
typedef long long ll;
const int N=310;
int vis[1001][1001];
int pos[N];
//int a[N];
int cnty,cntu,cnto;
char w[1001][1001];
int ans[100][100];
void cf()
{
	ll a,b,l,r;
	cin>>a>>b>>l>>r;
	ll tmp=b-a;
	
		ll k=tmp/l;//因为如果不能整除的话我们可以把倒二个l换成一个可能比l大的数
		ll q=(tmp+r-1)/r;//上取整如果不够的话必须多拿一个数
		if(k>t;
	while(t--)
	{
		cf();
	}
}

D题

其实后导0做法是挺常见的

就是看min(2因子,5因子)

2因子和5因子两个数里面较小的那个数决定了两个数相乘后0的个数

这题我们可以开一个ans[i][j]表示数里面2的因子有i个,5的因子有j个的数的个数

当两个数相乘的时候,其实就是把两个数2的因子个数相加,5的因子个数相加

然后0的个数就是两个因子个数取min就是了

举了例子把125*8

125:2的因子个数:0,5的因子个数3个

8:2的因子3个,5的因子0个

两个相乘之后2的因子0+3

5的因子3+0

最后得数x:2的因子3个,5的因子3个

min(3,3)=3所以最后后导0就有3个

当然ans[i][j]可能有很多个,也就是说有相同i个2因子和j个5因子的数之间是可以相乘的,

不同2因子和5因子之间也可以相乘

也就是说我们要处理两种情况

注意最后答案是要/2的因为是无序乘的结果会被算两个比如x*y和y*x本来是一种但是我们就会算成两种

#include
using namespace std;
typedef long long ll;
const int N=310;
int vis[1001][1001];
int pos[N];
//int a[N];
int cnty,cntu,cnto;
int ans[100][100];
void cf()
{
	int n,w;
	cin>>n>>w;
	vectorb(n+1);
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
	}
	for(int i=1;i<=n;i++)
	{
		int c1=0,c2=0;
		while(b[i]%2==0)
		{
			b[i]/=2;
			c1++;
		}
		while(b[i]%5==0)
		{
			b[i]/=5;
			c2++;
		}
		ans[c1][c2]++;//表示有c1个2因子和c2跟5因子的数有多少个 
	}
	ll sum=0;
	for(int i=0;i<=30;i++)
	{
		for(int j=0;j<=30;j++)
		{
			if(ans[i][j])
			{
				//同时2和5因子个数相同的数自己可以*
				if(min(i+i,j+j)>=w)
				{
					sum+=(ans[i][j])*(ans[i][j]-1);
				 } 
			}
		
				for(int p=0;p<=30;p++)
				{
					for(int q=0;q<=30;q++)
					{
						if(p==i&&q==j)continue;
						if(min(i+p,j+q)>=w)
						{
							sum+=(ans[i][j]*ans[p][q]);
						 } 
					}
				}
			
		}
	}
	 cout<

这里的循环30是看数据范围算出最多有多少个2因子和5因子,

你可能感兴趣的:(算法,数据结构)