欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

相关标签: 算法竞赛