• P5629 【AFOI-19】区间与除法 题解


    题目链接:P5629 【AFOI-19】区间与除法 题解

    线段树/ST表好题

    这道题目需要观察题目性质。

    机房考试的时候想出来了一个不用位运算的Tle做法,结果因为没开longlong直接见祖宗爆0了

    思路:

    不难发现,这道题的(m)给得很小,于是我们可以在给定的“原数”上下功夫。

    对于一个“原数”,我们假设一个数变为“原数”后,假设这个“原数”是(p),继续除以(d)能变为另外一个“原数”(q),那我们第一次得到的那个“原数”(p)显然没有继续除以(d)得到的那个“原数”(q)"优",因为我们可以简单的知道,能够还原成“原数”(p)的数一定可以还原成“原数”(q)

    我们这样消除后一些“原数”后,发现对于每一个数,要么它就不能被除成“原数”,要么就可以被除成唯一一个对应的“原数”,因为如果它可以得到两个及以上“原数”,根据上面提到的更小的“原数”更"优",那些大的“原数”都会被消除掉。

    我们可以预处理出每一个数可以被消成哪一个“原数”,因为(d) >= 2,对于每一个数处理的时间复杂度是(log)((数的大小))的,所以可以暴力预处理,时间复杂度为:O((nlog(n)))

    然后我们发现(m) <= 60 种,根据一开始的消除后会更小,于是想到状态压缩,但是我考试的时候没想那么多,就直接开一个bool数组,用线段树去维护区间出现的不同数的个数就行了,然而,这样子是会T的.......但是其实消除后的(m)可能并不是那么大,于是在luogu上吸口O2就过去了......题解里面都是ST表

    没有状态压缩的线段树,开O2过去了(不开会被卡成70pts)

    用时
    7.59s(最慢的一个点是2.18s)

    内存
    85.33MB

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 500005;
    long long n,m,d,p;
    long long a[MAXN] ,c[65], b[65],ss[65],Ans[65];
    int color[MAXN];
    
    struct tree {
    	bool book[61];
    	int l,r;
    } T[MAXN * 4];
    
    void Get(int x,int l,int r)
    {
    	if(T[x].l >= l && T[x].r <= r)
    	{
    		for(int i = 1 ; i <= m ; i ++)Ans[i] |= T[x].book[i];
    		return ;
    	}
    	int mid = ( T[x].l + T[x].r ) >> 1;
    	if(l <= mid)Get(x << 1 , l , r);
    	if(r  > mid)Get(x << 1 | 1 ,l , r );
    	return ;
    }
    
    void build(int x,int l,int r)
    {
    	T[x].l = l , T[x].r = r ;
    	if(l == r){T[x].book[color[l]] = 1;return ;}
    	int mid = (l + r) >> 1;
    	build(x << 1 , l , mid);
    	build(x << 1 | 1 , mid + 1 , r);
    	for(int i = 1 ; i <= m ; i ++)
    		if(T[x << 1].book[i] || T[x << 1 | 1].book[i])
    		T[x].book[i] = 1 ;
    	return ;
    }
    
    inline long long read()
    {
    	long long x = 0, flag = 1;
    	char ch = getchar();
    	for( ; ch > '9' || ch < '0' ; ch = getchar());
    	for( ; ch >= '0' && ch <= '9'; ch = getchar())x = (x << 3) + (x << 1) + ch - '0';
    	return x * flag;
    }
    
    inline void write(int x)
    {
    	if(!x){putchar('0'),putchar('
    ');return ;}
    	char W[30];
    	int R = 0;
    	while(x)
    		R ++ , W[R] = x % 10 + '0',x = x / 10;
    	for(int i = R ; i >= 1 ; i --)
    		putchar(W[i]);
    	putchar('
    ');
    	return ;
    }
    
    signed main()
    {
    	//freopen("purify.in","r",stdin);
    	//freopen("purify.out","w",stdout);
    	n = read() , m = read() , d = read() , p = read();
    	for(int i = 1 ; i <= n ; i ++)a[i] = read();
    	for(int i = 1 ; i <= m ; i ++)b[i] = read(),c[i] = 1;
    	sort(b + 1 , b + 1 + m);
    	for(int i = m ; i >= 1 ; i --)
    	{
    		long long t = b[i];
    		while(t && c[i] == 1)
    		{
    			for(int j = i - 1 ; j >= 1 ; j --)
    			if(b[j] == t)c[i] = 0;
    			t /= d;
    		}
    	}
    	int R = 0;
    	for(int i = 1 ; i <= m ; i ++)
    		if(c[i])R ++, ss[R] = b[i];//将消除后得到的"原数"拷贝
    	m = R;
    	for(int i = 1 ; i <= m ; i ++)
    		b[i] = ss[i];
    	for(int i = 1 ; i <= n ; i ++)
    	{
    		long long t = a[i],flag = 0;
    		while(t)
    		{
    			for(int j = 1 ; j <= m ; j ++)
    			if(t == b[j]){flag = 1 ; color[i] = j ;break;}
    			t /= d;
    		}
    	}
    	build(1 , 1 , n);
    	while(p)
    	{
    		long long l,r,ans = 0;
    		l = read() , r = read();
    		for(int i = 1 ; i <= m ; i ++)Ans[i] = 0;
    		Get(1,l,r);
    		for(int i = 1 ; i <= m ; i ++)
    			if(Ans[i] == 1)ans ++;
    		write(ans);
    		p --;
    	}
    	return 0;
    }
    

    然而,后来我想到了用bitset来搞

    用时
    3.89s

    内存
    36.86MB

    还是开了O2才过,内存以及时间上有了极大优化,不开被卡成80pts,因为据万神说,bitset有一个大常数

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 500005;
    long long n,m,d,p;
    long long a[MAXN] ,c[65], b[65],ss[65];
    bitset <61> Ans;
    int color[MAXN];
    
    struct tree {
    	bitset <61> book;
    	int l,r;
    } T[MAXN * 4];
    
    void Get(int x,int l,int r)
    {
    	if(T[x].l >= l && T[x].r <= r)
    	{
    		Ans |= T[x].book;
    		return ;
    	}
    	int mid = ( T[x].l + T[x].r ) >> 1;
    	if(l <= mid)Get(x << 1 , l , r);
    	if(r  > mid)Get(x << 1 | 1 ,l , r );
    	return ;
    }
    
    void build(int x,int l,int r)
    {
    	T[x].l = l , T[x].r = r ;
    	if(l == r){T[x].book[color[l]] = 1;return ;}
    	int mid = (l + r) >> 1;
    	build(x << 1 , l , mid);
    	build(x << 1 | 1 , mid + 1 , r);
    	T[x].book = T[x << 1].book | T[x << 1 | 1].book;
    	return ;
    }
    
    inline long long read()
    {
    	long long x = 0, flag = 1;
    	char ch = getchar();
    	for( ; ch > '9' || ch < '0' ; ch = getchar());
    	for( ; ch >= '0' && ch <= '9'; ch = getchar())x = (x << 3) + (x << 1) + ch - '0';
    	return x * flag;
    }
    
    inline void write(int x)
    {
    	if(!x){putchar('0'),putchar('
    ');return ;}
    	char W[30];
    	int R = 0;
    	while(x)
    		R ++ , W[R] = x % 10 + '0',x = x / 10;
    	for(int i = R ; i >= 1 ; i --)
    		putchar(W[i]);
    	putchar('
    ');
    	return ;
    }
    
    signed main()
    {
    	//freopen("purify.in","r",stdin);
    	//freopen("purify.out","w",stdout);
    	n = read() , m = read() , d = read() , p = read();
    	for(int i = 1 ; i <= n ; i ++)a[i] = read();
    	for(int i = 1 ; i <= m ; i ++)b[i] = read(),c[i] = 1;
    	sort(b + 1 , b + 1 + m);
    	for(int i = m ; i >= 1 ; i --)
    	{
    		long long t = b[i];
    		while(t && c[i] == 1)
    		{
    			for(int j = i - 1 ; j >= 1 ; j --)
    			if(b[j] == t)c[i] = 0;
    			t /= d;
    		}
    	}
    	int R = 0;
    	for(int i = 1 ; i <= m ; i ++)
    		if(c[i])R ++, ss[R] = b[i];
    	m = R;
    	for(int i = 1 ; i <= m ; i ++)
    		b[i] = ss[i];
    	for(int i = 1 ; i <= n ; i ++)
    	{
    		long long t = a[i],flag = 0;
    		while(t)
    		{
    			for(int j = 1 ; j <= m ; j ++)
    			if(t == b[j]){flag = 1 ; color[i] = j ;break;}
    			t /= d;
    		}
    	}
    	build(1 , 1 , n);
    	while(p)
    	{
    		long long l,r,ans = 0;
    		l = read() , r = read();
    		for(int i = 1 ; i <= m ; i ++)Ans[i] = 0;
    		Get(1,l,r);
    		for(int i = 1 ; i <= m ; i ++)
    			if(Ans[i] == 1)ans ++;
    		write(ans);
    		p --;
    	}
    	return 0;
    }
    

    最后放上不开O2也能过的状态压缩版

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 500005;
    long long n,m,d,p;
    long long a[MAXN] ,c[65], b[65],ss[65];
    long long Ans;
    int color[MAXN];
    
    struct tree {
    	long long book;
    	int l,r;
    } T[MAXN * 4];
    
    void Get(int x,int l,int r)
    {
    	if(T[x].l >= l && T[x].r <= r)
    	{
    		Ans |= T[x].book;
    		return ;
    	}
    	int mid = ( T[x].l + T[x].r ) >> 1;
    	if(l <= mid)Get(x << 1 , l , r);
    	if(r  > mid)Get(x << 1 | 1 ,l , r );
    	return ;
    }
    
    void build(int x,int l,int r)
    {
    	T[x].l = l , T[x].r = r ;
    	if(l == r){
    		if(color[l])
    		T[x].book |= (1ll << color[l]);
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build(x << 1 , l , mid);
    	build(x << 1 | 1 , mid + 1 , r);
    	T[x].book = T[x << 1].book | T[x << 1 | 1].book;
    	return ;
    }
    
    inline long long read()
    {
    	long long x = 0, flag = 1;
    	char ch = getchar();
    	for( ; ch > '9' || ch < '0' ; ch = getchar());
    	for( ; ch >= '0' && ch <= '9'; ch = getchar())x = (x << 3) + (x << 1) + ch - '0';
    	return x * flag;
    }
    
    inline void write(int x)
    {
    	if(!x){putchar('0'),putchar('
    ');return ;}
    	char W[30];
    	int R = 0;
    	while(x)
    		R ++ , W[R] = x % 10 + '0',x = x / 10;
    	for(int i = R ; i >= 1 ; i --)
    		putchar(W[i]);
    	putchar('
    ');
    	return ;
    }
    
    signed main()
    {
    	//freopen("purify.in","r",stdin);
    	//freopen("purify.out","w",stdout);
    	n = read() , m = read() , d = read() , p = read();
    	for(int i = 1 ; i <= n ; i ++)a[i] = read();
    	for(int i = 1 ; i <= m ; i ++)b[i] = read(),c[i] = 1;
    	sort(b + 1 , b + 1 + m);
    	for(int i = m ; i >= 1 ; i --)
    	{
    		long long t = b[i];
    		while(t && c[i] == 1)
    		{
    			for(int j = i - 1 ; j >= 1 ; j --)
    			if(b[j] == t)c[i] = 0;
    			t /= d;
    		}
    	}
    	int R = 0;
    	for(int i = 1 ; i <= m ; i ++)
    		if(c[i])R ++, ss[R] = b[i];
    	m = R;
    	for(int i = 1 ; i <= m ; i ++)
    		b[i] = ss[i];
    	for(int i = 1 ; i <= n ; i ++)
    	{
    		long long t = a[i],flag = 0;
    		while(t)
    		{
    			for(int j = 1 ; j <= m ; j ++)
    			if(t == b[j]){flag = 1 ; color[i] = j ;break;}
    			t /= d;
    		}
    	}
    	build(1 , 1 , n);
    	while(p)
    	{
    		long long l,r,ans = 0;
    		l = read() , r = read();
    		Ans = 0;
    		Get(1,l,r);
    		while(Ans)
    		{
    			ans++;
    			Ans-=(Ans&-Ans);
    		}
    		write(ans);
    		p --;
    	}
    	return 0;
    }
    
  • 相关阅读:
    Exchanger
    信号量Semaphore
    CountDownLatch
    Condition
    WCF接口实例介绍
    时间显示
    pymysql-execute
    python之迭代器与生成器
    python之装饰器
    python之函数
  • 原文地址:https://www.cnblogs.com/MYCui/p/13921090.html
Copyright © 2020-2023  润新知