NOIP2023 国庆集训 A 组 Day5

T1

 k <= 10,n <= 5e6

思路:首先我们可以观察到k的值很小,一共只有4k个状态即最大就只有220个状态,因此可以将这些状态存起来。

这里计算一个串的 Hash 值有两种方法,第一种是每个串都重新计算一遍,时间复杂度为O(nk),第二种是利用位运算将无用状态取出,并加入新状态,时间复杂度为O(n) 。这两个复杂度的代码均可通过。

限制位数的小妙招如果只有两种状态则将状态h &= (1 << (k - 1) - 1,就能将最高位去掉

注意:位运算最好加括号避免优先级搞错

AC代码

#include <bits/stdc++.h>

using namespace std;
const int N = 5e6 + 10; 
int d[N],n,m,k,cnt[1 << 20],f[27],h,ans;
char a[N];
int main(){
	freopen("dna.in","r",stdin);
	freopen("dna.out","w",stdout);
	f['G' - 'A'] = 1;
    f['C' - 'A'] = 2;
    f['T' - 'A'] = 3;
	scanf("%s",a);
	n = strlen(a);
	cin >> k;
	int m = (1 << ((k - 1) << 1)) - 1;
	for(int i = 0;i < n;i++) d[i] = f[a[i] - 'A'];
	for(int i = 0;i <= k - 2;i++) h = h << 2 | d[i];
	for(int i = k - 1;i < n;i++){
		h = h << 2 | d[i];
		++cnt[h];
		h &= m;
	}
	for(int i = 0;i < (1 << (k << 1));i++) ans = max(ans,cnt[i]);
	cout << ans;
	return 0;
} 

T2

思路:线性筛加前缀和

AC代码
 #include <bits/stdc++.h>

using namespace std;
const int N = 1e7 + 10;
int p[N],cnt,vis[N],sum[N];
bool can[N];
void pre(){
	for(int i = 2;i <= 10000000;i++){
		if(!vis[i]){
			p[++cnt] = i;
			can[i] = i;
			for(int j = 1;j <= cnt && i * p[j] <= 10000000;j++){
				vis[i * p[j]] = 1;
				can[i * p[j]] = 1;
			}
		}
		else{
			for(int j = 1;j <= cnt && i * p[j] <= 10000000;j++){
				vis[i * p[j]] = 1;
				if(i % p[j] == 0) break; 
			}
		}
	}
	for(int i = 1;i <= 10000000;i++) sum[i] = sum[i - 1] + can[i];
} 
int main(){
	freopen("prime.in","r",stdin);
	freopen("prime.out","w",stdout);
	int q;
	pre();
	cin >> q;
	while(q--){
		int l,r;
		cin >> l >> r;
		cout << sum[r] - sum[l - 1] << endl;
	}
	return 0;
}

 

posted @ 2023-10-06 15:26  LouYW07  阅读(24)  评论(0)    收藏  举报