2018计蒜之道 初赛 第二场
程序员文章站
2022-03-14 23:16:34
...
A.淘宝推荐系统
题面链接:https://nanti.jisuanke.com/t/26984
直接暴力dp就行
.....代码赛后没保存Orz....找不到了
B.阿里巴巴的手机代理商(简单)
题目链接:https://nanti.jisuanke.com/t/26985
直接拿map暴力就行
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<iostream>
#include<stdlib.h>
using namespace std;
#define LONG long long
const int INF=0x3f3f3f3f;
const LONG MOD=1e9+ 7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson l , mid , rt<< 1
#define rson mid + 1 ,r , (rt<<1)+1
#define root 1, m , 1
map<string , int > mp ;
int main()
{
int T;
cin >> T ;
while(T -- )
{
mp.clear() ;
int n;
cin >> n ;
string tmp , op;
int val ;
for(int i = 1; i <= n ; ++ i)
{
cin >> op ;
if(op[0] == 'i')
cin >> tmp >> val ,mp[tmp] += val ;
else if(op[0] == 'd')
{
cin >> tmp ;
if(mp[tmp] == 0)
cout<<"Empty"<<endl;
mp[tmp] = 0 ;
}
else
{
cin >> tmp ;
int ans = 0 ;
for(auto it = mp.begin() ; it != mp.end() ; ++it)
{
string ss = it->first ;
if(ss.length() < tmp.length()) continue ;
string res = "";
for(int j = ss.length() - tmp.length() ; j < ss.length() ; ++ j)
res.push_back(ss[j]) ;
if(res == tmp) ans += it->second ;
}
cout<<ans<<endl;
}
}
}
}
C.阿里巴巴的手机代理商(中等)
题目链接:https://nanti.jisuanke.com/t/26986
把字符串倒着插到字典树里面,注意单词和后缀是不一样的,即delete操作和query,update操作的区别
然后换后缀的时候:
1、把后缀str1的儿子和当前后缀str1的信息记录;
2、删去它的所有儿子并且清空对应的信息;
3、把(1)中记录的信息和儿子赋给后缀str2;
注意上面的顺序不能打乱,不可以先赋给str2再清空,因为存在str1是str2的一个后缀的情况,如 update cd abcd
细节还是有点繁琐的:
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<iostream>
#include<stdlib.h>
using namespace std ;
#define LONG long long
const int INF=0x3f3f3f3f;
const LONG MOD=1e9+ 7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson l , mid , rt<< 1
#define rson mid + 1 ,r , (rt<<1)+1
#define root 1, m , 1
struct Node
{
int next[26]; //每个几点里面存的是一个指针 用第几个申请的来表示
LONG cnt ,tag ;
void Init()
{
tag = 0 ;
cnt = 0;
clrI(next); //初始化为-1 代表这个节点尚未被申请 是NULL的
}
}L[1000000+11];
int tot = 0;
void Insert(char a[] , LONG val )
{
int now =0 ;
int len = strlen(a) ;
for(int i = 0 ; i < len ; ++ i)
{
int tmp = a[i] - 'a' ;
int temp = L[now].next[tmp] ;
now = temp ;
}
L[now].tag += val ;
}
LONG Query_Tag(char a[])
{
int now = 0;
int len = strlen(a) ;
for(int i = 0 ; i < len ; ++ i)
{
int tmp = a[i] - 'a' ;
int temp = L[now].next[tmp] ;
if(temp == -1) return 0ll ;
now = temp ;
}
return L[now].tag ;
}
int creatTrie(char a[] , LONG val )
{
int now = 0 ;
int len = strlen(a);
for( int i = 0 ; i < len ; ++ i )
{
int tmp=a[i]-'a';
int nextt=L[now].next[tmp];
if(nextt==-1)
{
tot ++ ;
L[tot].Init();
L[now].next[tmp]= tot ;
nextt = tot ;
}
L[nextt].cnt += val ;
now = nextt;
}
return now ;
}
void Update(char a[] , LONG val )
{
int len = strlen(a) ;
int now = 0 ;
for(int i = 0 ; i< len ; ++ i)
{
int tmp = a[i] - 'a' ;
int nextt = L[now].next[tmp] ;
if(nextt ==-1) return ;
L[nextt].cnt -= val ;
now = nextt ;
}
L[now].tag -= val ;
}
LONG query( char a[] )
{
int len = strlen(a);
int now = 0;
for(int i = 0 ; i < len ;++i)
{
int tmp = a[i] - 'a';
int nextt = L[now].next[tmp];
if ( nextt == -1)
return 0ll;
now = nextt;
}
return L[now].cnt;
}
void Change(char a[] , char b[] )
{
int len = strlen(a) ;
int now = 0 ;
for(int i = 0 ; i <len ; ++ i)
{
int tmp = a[i] - 'a' ;
int nextt = L[now].next[tmp] ;
now = nextt ;
}
//
LONG num = L[now].cnt ;
LONG num1 = L[now].tag ;
int cc [26] ;
for(int i = 0 ;i < 26 ; ++ i)
cc[i] = L[now].next[i] ;
Update(a , num) ;
L[now].Init() ;
//
int temp = creatTrie(b,num) ;
for(int i = 0 ; i < 26 ; ++ i)
L[temp].next[i] = cc[i] ;
L[temp].tag = num1 ;
}
char str1[1001000] ;
char str2[1001000] ;
void Reverse(char *a)
{
int len =strlen(a) ;
for(int i = 0 ; i < (len>>1) ; ++ i)
swap(a[i] , a[len - i -1]) ;
}
int main()
{
int T ;
scanf("%d",&T) ;
while(T --)
{
tot = 0 ;
L[0].Init();
int n ;
scanf("%d",&n) ;
char op[20] ;
LONG val ;
for(int i = 1; i<= n ; ++ i)
{
scanf("%s",op) ;
if(op[0] == 'i')
{
scanf("%s%lld",str1 ,&val) ;
Reverse(str1) ;
creatTrie(str1 , val) ;
Insert(str1 , val) ;
}
else if(op[0] == 'd')
{
scanf("%s",str1) ;
Reverse(str1) ;
LONG res = Query_Tag(str1) ;
if(res <= 0 )
printf("Empty\n") ;
else Update(str1 , res) ;
}
else if(op[0] == 'q')
{
scanf("%s",str1) ;
Reverse(str1) ;
LONG res = query(str1) ;
printf("%lld\n",res) ;
}
else
{
scanf("%s%s",str1,str2) ;
Reverse(str1) ;
Reverse(str2) ;
LONG res1 = query(str1) ;
LONG res2 = query(str2) ;
if(res1 <= 0)
{
printf("Empty\n") ;continue ;
}
if(res2 >= 1 || Query_Tag(str2) >= 1)
{
printf("Conflict\n") ; continue ;
}
Change(str1,str2) ;
}
}
for(int i = 0 ;i <= tot ; ++ i)L[i].Init() ;
}
}
D.阿里巴巴的手机代理商(困难)
数据范围和基本操作跟中等版本一样,多出了一个查询历史版本的操作,应该是把trie树用可持久化trie去替代就行了:
insert :每次更新一条链;
delete :同上;
update:每次更新2条链,把后缀str1和str2的链都更新了;
query:直接查询当前版本;
vquery: 当前的版本往后退,然后查询就行了;
(理论AC,日常口胡,然而代码并没有打完,数据结构能力低下的一匹.....Orz。)
上一篇: 最长公共子序列问题
推荐阅读
-
【计蒜客】2018ICPC徐州赛区网络赛H Ryuji doesn't want to study(树状数组)
-
计蒜客 Trace(2018 ICPC亚洲区域赛网络赛 徐州 G)(线段树)
-
2016计蒜之道复赛 百度地图的实时路况(Floyd 分治)
-
智算之道初赛第二场A题
-
2020 计蒜之道 线上决赛(C,D,E,F,G)
-
【计蒜客】2018ICPC焦作赛区网络赛K Transport Ship(多重背包+dp)
-
【计蒜客】2018ICPC南京赛区网络赛G Lpl and Energy-saving Lamps(线段树)
-
【计蒜客】2018ICPC南京赛区网络赛J Sum(素数筛+找规律)
-
【计蒜客】2018ICPC徐州赛区网络赛F Features Track(map的使用)
-
贝壳找房性价比(2018 计蒜之道 初赛 第三场)