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;
}

浙公网安备 33010602011771号