第一题
[编程题]用户喜好
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 256M,其他语言512M
为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为k。因为一些特殊的原因,不会出现一个查询的用户区间完全覆盖另一个查询的用户区间(不存在L1<=L2<=R2<=R1)。
输入描述:
输入: 第1行为n代表用户的个数 第2行为n个整数,第i个代表用户标号为i的用户对某类文章的喜好度 第3行为一个正整数q代表查询的组数 第4行到第(3+q)行,每行包含3个整数l,r,k代表一组查询,即标号为l<=i<=r的用户中对这类文章喜好值为k的用户的个数。 数据范围n <= 300000,q<=300000 k是整型
输出描述:
输出:一共q行,每行一个整数代表喜好值为k的用户的个数
输入例子1:
5
1 2 3 3 5
3
1 2 1
2 4 5
3 5 3
输出例子1:
1
0
2
例子说明1:
样例解释:
有5个用户,喜好值为分别为1、2、3、3、5,
第一组询问对于标号[1,2]的用户喜好值为1的用户的个数是1
第二组询问对于标号[2,4]的用户喜好值为5的用户的个数是0
第三组询问对于标号[3,5]的用户喜好值为3的用户的个数是2
莫队裸题
离线区间统计问题可以考虑使用莫队来维护
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N = 3e5+5;
int n,m,block,a[N],ans[N],ANS[N];
struct query{
int l, r, k, id;
}q[N];
bool cmp(const query &a, const query &b){
return (a.r/block) == (a.r/block) ? a.l<b.l : a.r<b.r;
}
void del(int x){
ANS[a[x]]--;
}
void add(int x){
ANS[a[x]]++;
}
int main(){
scanf("%d",&n);
fo(i,1,n)scanf("%d",&a[i]);
scanf("%d",&m);
fo(i,1,m){
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
q[i].id = i;
}
block = n/sqrt(m);
sort(q+1,q+1+m,cmp);
int l=1,r=0;
fo(i,1,m){
int ql=q[i].l,qr=q[i].r,qk=q[i].k,qid=q[i].id;
while(r>qr)del(r--);
while(l<ql)del(l++);
while(r<qr)add(++r);
while(l>ql)add(--l);
ans[qid] = ANS[qk];
}
fo(i,1,m){
printf("%d\n",ans[i]);
}
return 0;
}
第二题
链接:https://www.nowcoder.com/questionTerminal/8da0ea4b4853464795f5c32634a1b06f
来源:牛客网
[编程题]字母交换
热度指数:1995时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 32M,其他语言64M
算法知识视频讲解
【编码题】字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?
输入描述:
第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)
输出描述:
一个非负整数,表示操作之后,连续最长的相同字母数量。
示例1
输入
abcbaa 2
输出
2
说明
使2个字母a连续出现,至少需要3次操作。即把第1个位置上的a移动到第4个位置。
所以在至多操作2次的情况下,最多只能使2个b或2个a连续出现。
直接暴力模拟每个环就好啦
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=1e4+5;
int n,m,c;
vector<int> color[N];
bool ok[55];
int num[55];
int main(){
scanf("%d%d%d",&n,&m,&c);
fo(i,1,n){
int t;scanf("%d",&t);
while(t--){
int x;scanf("%d",&x);
color[i].push_back(x);
}
}
fo(i,1,m){
for(int j=0; j<color[i].size(); j++){
if(++num[color[i][j]]>=2){
ok[color[i][j]]=1;
}
}
}
fo(i,2,n){
int l = i-1;
int r = (i+m-2)%n + 1;
for(int j=0; j<color[l].size(); j++){
num[color[l][j]]--;
}
for(int j=0; j<color[r].size(); j++){
if(++num[color[r][j]]>=2){
ok[color[r][j]]=1;
}
}
}
int ans = 0;
fo(i,1,c){
if(ok[i])ans++;
}
printf("%d\n",ans);
return 0;
}
第三题
程题]字母交换
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32M,其他语言64M
【编码题】字符串S由小写字母构成,长度为n。定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换。询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同?
输入描述:
第一行为一个字符串S与一个非负整数m。(1 <= |S| <= 1000, 1 <= m <= 1000000)
输出描述:
一个非负整数,表示操作之后,连续最长的相同字母数量。
输入例子1:
abcbaa 2
输出例子1:
2
例子说明1:
使2个字母a连续出现,至少需要3次操作。即把第1个位置上的a移动到第4个位置。
所以在至多操作2次的情况下,最多只能使2个b或2个a连续出现。
类似区间DP问题…我居然没做出来,我太菜了
dp[i][j] 标识第i个到第j个相同字母移动在一起的最少交换次数
v[i]表示第i个字母位置
dp[i][j] = dp[i+1][j-1]+(v[j]-v[i]-1) - (j-i-1);
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=1005;
//char s[N];
int m, ans;
vector<int> c[27];
int dp[N][N];
string s;
// dp[i][j] 标识第i个到第j个移动在一起的最少交换次数
// dp[i][j] = dp[i+1][j-1] + (c[字母][j]-c[字母][i]-1) - (j-i-1)
void calc(const vector<int> & v){
int n = v.size();
memset(dp,0,sizeof(dp));
for(int i=0; i+1<n; i++){
dp[i][i+1] = v[i+1]-v[i]-1;
}
// 区间dp思想, 距离,起点,断点(这里没有)
for(int r=2; r<n; r++){
for(int i=0; i+r<n; i++){
int j=i+r;
dp[i][j] = dp[i+1][j-1]+(v[j]-v[i]-1) - (j-i-1);
}
}
for(int i=0; i<n; ++i){
for(int j=i+1; j<n; ++j){
if(dp[i][j]<=m){
ans = max(ans, j-i+1);
}
}
}
}
void solve(){
int len = s.length();
// 每个字母
fo(i,0,len-1){
c[s[i]-'a'].push_back(i);
}
if(len>=1)ans=1;
fo(i,0,25){
calc(c[i]);
}
printf("%d\n", ans);
}
int main(){
// scanf("%s %d", s+1, &m);
cin >> s >> m;
solve();
return 0;
}