CF Round#626

CF Round#626

A.水~##

B.数学##

题意:

分别给定你两个长度为n,m的字符串A,B,都是由0,1构成

矩阵每个元素aij=Ai*Bj

现在给定k,问这个矩阵当中有多少个子矩阵,使得子矩阵的所有元素为1,且1的数量刚好为k

思路:

这道题目看起来很难,但是稍加分析,不难发现,所求的k是个面积,那么面积就应该由长乘宽组成,换句换说,我们现在就是要将k进行拆解两个整数,使得k=m * (k/m),那么为了子矩阵内全是1,那么我们无非就要使长或宽均是1。

那么问题就转变成了在A上寻找一段长度为m连续为1的子串,B上寻找长度为k/m连续为1的子串,根据乘法原理,相乘即可。

那么问题的关键点就成为了长度为k,连续为1的子串有多少

On 的做法就是从左往右扫一遍,初始化cur=0,遇到1,cur++,savea[cur]++;遇到0,cur=0;

处理后,再从右往左扫一遍,savea[i-1]+=savea[i],这样做的目的模拟一下下就懂了,savea[x]就是长度为x的数量了


#include<iostream>
#include<cstring>
#include<cmath>	
using namespace std;
#define INF 1e10+5
#define MAXN 50010
#define MINN -105
typedef long long int LL;
int main()
{	
	LL n,m,k;
	LL a[MAXN],b[MAXN],savea[MAXN],saveb[MAXN];
	memset(savea,0,sizeof(savea));
	memset(saveb,0,sizeof(saveb));
	cin>>n>>m>>k;
	LL cur=0;
	for(LL i=1;i<=n;i++)
	{
	    cin>>a[i];
	    if(a[i])cur++;
	    else cur=0;
	    savea[cur]++;
	}
	for(LL i=n;i>=2;i--)
    	savea[i-1]+=savea[i];
	cur=0;
	for(LL i=1;i<=m;i++)
	{
	    cin>>b[i];
	    if(b[i])cur++;
	    else cur=0;
	    saveb[cur]++;
	}
	for(LL i=m;i>=2;i--)
	    saveb[i-1]+=saveb[i];
	LL ans=0;
	for(LL i=1;i<=k;i++)
	{
	    if(i>n)break;
	    if((k/i)>m)continue;
	    if(k/i*i==k)
	        ans+=savea[i]*saveb[k/i];
	}
	cout<<ans<<endl;
	return 0;
}

C.模拟##

这题看懂题目意思很重要,他是给一个字符串由 () 组成,问你最小操作长度多长,使得括号匹配正确。每次操作可以任意调换长度内的顺序.

思路:首先,他只能调换顺序,也就是是"("和")"的数量要一样,其次,你从左往右扫,to记录当前(的数量,如果为正,说明(比)多多少,也就是是只要为正就可以完全抵消,如果为负,那么要记录te,进行交换的区间是多长,一旦to==0,那么就要更新ans,清空te

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
#define INF 1e10+5
#define MAXN 105
#define MINN -105
typedef long long int LL;
int main() 
{
	int n ;
	string s ;
	cin>>n>>s;
	int c=0,to=0,te=0,ans=0;
	for(int i=0;i<n;++i)(s[i]==')')?--c:++c ;
	if(c){cout<<-1<<endl;return 0;}
	for(int i=0;i<n;++i)
	{
	    if(s[i]=='(')
		{
   	    	if(to<0)te++;
        	to++;
    	}
   	 	else to--;
   		if(to==0)ans+=(te*2),te=0;
	}
cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/et3-tsy/p/12444747.html