2018计蒜之道 初赛 第二场

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。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值