• 【HDU6345】子串查询【前缀和】【线段树】


    题目大意:

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6345
    求给定串llrr的位置里字典序最小的字串出现的次数。


    思路:

    字典序最小的串,肯定是一个字符啊。
    可以用线段树维护一下。时间复杂度O(Tq logn)O(Tq\ logn)
    当然也可以用前缀和。时间复杂度O(t(q+n))O(t(q+n))


    代码:

    线段树:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define N 1000100
    using namespace std;
    
    int n,t,m;
    char c[N];
    
    struct node
    {
    	int l,r,sum;
    	char c;
    }tree[N*3];
    
    void make(int x)  //建树
    {
    	if (tree[x].l==tree[x].r) 
    	{
    		tree[x].c=c[tree[x].l];
    		tree[x].sum=1;
    		return;
    	}
    	int mid=(tree[x].l+tree[x].r)/2;
    	tree[x*2].l=tree[x].l;
    	tree[x*2].r=mid;
    	tree[x*2+1].l=mid+1;
    	tree[x*2+1].r=tree[x].r;
    	make(x*2);
    	make(x*2+1);
    	if (tree[x*2].c==tree[x*2+1].c)  //最小字符和出现次数更改
    	{
    		tree[x].c=tree[x*2].c;
    		tree[x].sum=tree[x*2].sum+tree[x*2+1].sum;
    	}
    	else if (tree[x*2].c<tree[x*2+1].c)
    	{
    		tree[x].c=tree[x*2].c;
    		tree[x].sum=tree[x*2].sum;
    	}
    	else
    	{
    		tree[x].c=tree[x*2+1].c;
    		tree[x].sum=tree[x*2+1].sum;
    	}
    	return;
    }
    
    int find(int x,int l,int r)
    {
    	if (tree[x].l==l&&tree[x].r==r)
    	 return tree[x].sum*100+(int)(tree[x].c-'A');
    	//这里用到了一些小技巧,本来要返回一个字符和出现次数的,但是我直接返回出现次数*100再加上字符的ASCII码值-A的ASCII码值
    	if (tree[x].l==tree[x].r) 
    	 return 0;
    	int mid=(tree[x].l+tree[x].r)/2;
    	if (r<=mid) return find(x*2,l,r);
    	if (l>mid) return find(x*2+1,l,r);
    	int a=find(x*2,l,mid);
    	int b=find(x*2+1,mid+1,r);
    	if (a%100<b%100) return a;
    	if (a%100>b%100) return b;  //取出字符和ASCII码
    	return (a/100+b/100)*100+a%100;  //更新
    }
    
    int main()
    {
    	scanf("%d",&t);
    	int x,y;
    	for (int q=1;q<=t;q++)
    	{
    		scanf("%d%d",&n,&m);
    		cin>>c+1;
    		tree[1].l=1;
    		tree[1].r=n;
    		make(1);
    		printf("Case #%d:\n",q);
    		while (m--)
    		{
    			scanf("%d%d",&x,&y);
    			int a=find(1,x,y);
    		    printf("%d\n",a/100);
    		}
    	}
    	return 0;
    }
    

    前缀和:

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #define N 1000100
    using namespace std;
    
    int s[N][30],t,n,m,l,r;
    char c[N];
    
    int main()
    {
    	scanf("%d",&t);
    	for (int q=1;q<=t;q++)
    	{
    		memset(s,0,sizeof(s));
    		scanf("%d%d",&n,&m);
    		cin>>c+1;
    		for (int i=1;i<=n;i++)
    		 s[i][c[i]-'A'+1]++;
    		for (int i=1;i<=n;i++)
    		 for (int j=1;j<=26;j++)
    		  s[i][j]+=s[i-1][j];
    		printf("Case #%d:\n",q);
    		while (m--)
    		{
    			scanf("%d%d",&l,&r);
    			for (int i=1;i<=26;i++)
    			 if (s[r][i]-s[l-1][i])
    			 {
    			 	printf("%d\n",s[r][i]-s[l-1][i]);
    			 	break;
    			 }
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    错误论:错误是人类实践结果的一种状态,是实践的一个中间环节
    逻辑思维
    正确与错误、真理与谬误
    正确的判断,来自于错误的判断
    PHP+MySQL实现对一段时间内每天数据统计优化操作实例
    centos linux ip地址无法连接数据库,ssh登录服务器时必须使用22端口
    如何更改linux文件目录拥有者及用户组
    navicat ssh通道受限问题处理
    Navicat for MySQL 使用SSH方式链接远程数据库(二)
    Navicat for MySQL 使用SSH方式链接远程数据库
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998529.html
Copyright © 2020-2023  润新知