A1129
个人思路
题意:对英文阅读理解有一定要求,我就是卡在Access这个词上(应译为访问),结果一直不明白这道题的含义
给出用户点击item的次序,要系统根据用户对item的点击次数(最大的优先推荐,次数相等推荐编号最小的),在用户下一次点击item前,给出推荐item编号,推荐个数最多不超过K个
PS:第一个item没有推荐,因为之前没有访问记录
关键:要完成边插入边排序,在序列打乱的情况下快速访问插入
个人思考过程:
- 结构体,能很好的排序但发现无法快速访问,如何能在排序后快速访问(暴力求解,至少能得一半的分数)
- map,能快速访问,但无法按题目要求排序
- multimap,按键排序,值只是按先后顺序
思路:
然后看了几个大佬的博客,才知道此题是使用STL容器存储结构体,并重载运算符(没错,这样可以随心所欲的排序)进行增删改查。读入数据时,查询集合中数据是否存在,若存在则先删除再插入,不存在直接插入即可
自己在实现过程中还是遇到了一些问题:
- 一开始重载运算符使用的是声明友元函数(依照优先队列重载运算符的方法),此时会报错
- STL(结构体)查找时是会比较结构体中的所有成员,所有数据一致为查找成功。要注意 点击次数自增代码的位置(cntAccess[data]++;),应该在查找后再自增,如果在查找前就已经自增了,则永远不会比对成功
暴力代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 50005;
int N, K;
struct Rec{
int data;
int cnt;
}rec[maxn];
bool cmp(Rec r1, Rec r2)
{
if(r1.cnt != r2.cnt)
return r1.cnt > r2.cnt;
else
return r1.data < r2.data;
}
int cntAccess[maxn];
multimap<int, int> cnt2id;
int main(int argc, char *argv[]) {
scanf("%d%d", &N, &K);
int size = 0;
for(int i = 0; i < N; ++i)
{
int data;
scanf("%d", &data);
rec[i].data = data;
if(i != 0)
{
sort(rec, rec + i + 1, cmp);
printf("%d: ", data);
for(int j = 0; j < min(K, size); ++j)
{
printf("%d", rec[j].data);
if(j < min(K, size) - 1)
printf(" ");
else
printf("\n");
}
size++;
}
for(int j = 0; j <= i; ++j)
{
if(rec[j].data == data)
{
rec[j].cnt++;
break;
}
}
if(i == 0)
{
size++;
continue;
}
}
return 0;
}
AC代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 50005;
int N, K;
struct Rec{
int data;
int cnt;
bool operator < (const Rec &r1)const
{
if(r1.cnt != cnt)
return cnt > r1.cnt;//cnt大的排在前面
else
return data < r1.data;//data小的排在前面
}
/*friend bool operator < (Rec r1, Rec r2)//会出错
{
if(r1.cnt != r2.cnt)
return r1.cnt < r2.cnt;//cnt大的排在前面
else
return r1.data > r1.data;//data小的排在前面
}*/
Rec(){}
Rec(int dd, int cc)
{
data = dd;
cnt = cc;
}
};
set<Rec> st;
int cntAccess[maxn];
int main(int argc, char *argv[]) {
scanf("%d%d", &N, &K);
int data;
scanf("%d", &data);
cntAccess[data]++;
st.insert(Rec(data, cntAccess[data]));
for(int i = 1; i < N; ++i)
{
scanf("%d", &data);
printf("%d:", data);
int num = 0;
for(set<Rec>::iterator j = st.begin(); j != st.end(); ++j)
{
if(num < K)
printf(" %d", j->data);
else
break;
num++;
}
printf("\n");
set<Rec>::iterator it = st.find(Rec(data, cntAccess[data]));//先查询,此时cntAccess不做自增操作
if(it != st.end())//集合中存在当前数据
st.erase(it);//删除重新插入更新
cntAccess[data]++;//查询后再做自增操作
st.insert(Rec(data, cntAccess[data]));//直接插入
}
return 0;
}