求区间[L,R]内某个数出现的次数(二分/分块)

https://ac.nowcoder.com/acm/contest/13504/E

大意


给出n个贝壳,每个贝壳上有一个编号,q次询问,每次询问在区间[L,R]内有多少个是x的倍数。

思路


用vector保存每个数的下标,所有a[x]中就会保存x在数组中所有的下标,并且我们是按顺序添加的,所有下标是递增的,然后枚举所有小于等于最大编号并且是x的倍数的编号,二分查找这个数的所有满足在[L,R]内数有多少个。

code


#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 2e6+7;
const int ds = 1e8+7;
const int base = 233;
const double PI = 3.141592653589793238462643383;
 
using namespace std;

int a[N];
vector<int>b[N];
void solve() {
	int n,q,mmax = 0;
	cin >> n >> q;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		b[a[i]].push_back(i);
		mmax = max(mmax,a[i]);
	}
	while(q--){
		int l,r,x;
		cin >> l >> r >> x;
		int ans = 0;
		for(int i = x; i <= mmax; i += x){
			if(b[i].size() == 0) continue;
			int xb1 = lower_bound(b[i].begin(),b[i].end(),l) - b[i].begin();
			int xb2 = upper_bound(b[i].begin(),b[i].end(),r) - b[i].begin();
			ans += xb2-xb1;
		}
		cout << ans << endl;
	}
}

int main() { 
//	int t;
//	scanf("%d",&t);
//	while(t--)
		solve();
	return 0;
}

 

https://ac.nowcoder.com/acm/contest/12478/A

大意


如果两个字符串,通过不同的字目映射关系可以转换为一样的中文意思,那么称这两个暗号本质相同,比如“lff”,“dee”,“kbb”“lff”,“dee”,“kbb”“lff”,“dee”,“kbb”都是本质相同的。

其实也就是成语中的AABB形,ABAB形成语这种说法。如果给出n个串,q次询问,问[L,R]与串t本质相同的个数。

思路


先处理n个串,判断每个串是哪种形的,利用数字来表示,比如1212,就是ABAB形,1122就是AABB形,然后用map<string,vector<int>>mp去保存这种形的串的下标。

然后q次询问的时候先判断t是哪种形的串,同样利用二分去查找下标在[L,R]内有多少个。

code


#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int N = 1e7+7;
const ll ds = 1e15+7;
const double PI = 3.141592653589793238462643383;
 
using namespace std;

map<string,vector<int> >mp;
char s[505];
int vis[30];
void solve()
{
	int n,q,t;
	scanf("%d%d",&n,&q);
	for(int i = 1; i <= n; i++){
		scanf("%s",s);
		memset(vis,0,sizeof vis);
		string s1 = "";
		t = 0;
		for(int j = 0; j < strlen(s); j++){
			if(!vis[s[j]-'a']){	
				s1 += (++t);
				vis[s[j]-'a'] = t;
			}
			else s1 += vis[s[j]-'a'];
		}
		mp[s1].push_back(i);
	}
	while(q--){
		int l,r,lxb,rxb;
		scanf("%s%d%d",s,&l,&r);
		memset(vis,0,sizeof vis);
		string s1 = "";
		t = 0;
		for(int j = 0; j < strlen(s); j++){
			if(!vis[s[j]-'a']){	
				s1 += (++t);
				vis[s[j]-'a'] = t;
			}
			else s1 += vis[s[j]-'a'];
		}
		lxb = lower_bound(mp[s1].begin(),mp[s1].end(),l)-mp[s1].begin();
		rxb = upper_bound(mp[s1].begin(),mp[s1].end(),r)-mp[s1].begin();
		printf("%d\n",rxb-lxb);
	}
}

int main() {
//	int t;
//	scanf("%d",&t);
//	while(t--)
		solve();
	return 0;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值