2018 UESTC Training for Search Algorithm & String

6 篇文章 1 订阅
5 篇文章 0 订阅

2018 UESTC Training for Search Algorithm & String

最近考试结课作业什么的有点多,在实验室也静不下心学新的东西,东逛西逛到了CDOJ然后发现了这个contest,于是乎做了一些题。

传送门

A - 多少片不同的叶子?

题意:计算有多少个不同的字符串

解:拿到直接 map m a p 了,然后mle on test5,一看只给了10M,那还能怎么办,字符串哈希呗。

个人感觉这题卡的也是有点紧,能vector全vector然后能局部就局部才过

大家感受一下
这里写图片描述

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

const int D1=131;

const int MOD1=1e9+7;


vector<int> hash1;


int make_hash1(string s)
{
    int ans=0;
    for(int i=0;i<s.size();i++)
     ans=(ans*D1+(s[i]))%MOD1;
    return ans;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        string ss;
        cin>>ss;
        hash1.push_back(make_hash1(ss));
    }
    sort(hash1.begin(),hash1.end());
    int cnt=1;
    for(int i=1;i<n;i++)
        if(hash1[i]!=hash1[i-1]) cnt++;
    printf("%d",cnt);
}

B - 假装我是一个AC自动机

题意:没啥好说的,模拟一下就过了(代码略搓)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

string s[100005];

int powmod(int a,int b)
{
    ll res=1;
    for(; b; b>>=1)
    {
        if(b&1)res=res*a;
        a=a*a;
    }
    return res;
}


int cal(string ss)
{
//    cout<<pow(10,0)<<endl;
    int ans=0;
    int len=ss.size();
    for(int i=0; i<len; i++)
    {
        ans+=(int)(ss[i]-'0')*powmod(10,len-i-1);
//        cout<<ans<<endl;
    }
    return ans;
}

bool check(char c)
{
    if(c<='z'&&c>='a')
        return true;
    if(c<='Z'&&c>='A')
        return true;
    return false;
}

void debug()
{
    string xs="125";
    cout<<cal(xs)<<endl;
}
int main()
{
//    debug();
    int pos=0;
    string num="";
    int flag=0;
    string ms;
    cin>>ms;
    for(int i=0; i<ms.size(); i++)
    {
        char ch=ms[i];
        if(check(ch))
            s[pos]+=ch;
        else if(ch==';')
        {
            cout<<s[pos]<<endl;
            pos++;
            continue;
        }
        else if(ch=='#')
        {
            s[pos]="";
            continue;
        }
        else if(ch=='@')
        {
            if(!flag)
            {
                flag=1;
                num="";
            }
            else
            {
                int sum=cal(num);
//                cout<<sum<<endl;
                if(pos-sum>=0)
                    s[pos]+=s[pos-sum];
                flag=0;
            }
            continue;
        }
        if(flag)
        {
            if(ch!='@')
                num+=ch;
            continue;
        }
        if(i==ms.size()-1)
        {
            cout<<s[pos];
        }
    }
}

C - 不骗你这题真的是送分的

题意:这题啊,又是一个字符串哈希的裸题,无发可嗦

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

const int base = 163;

char s[100005];

unsigned long long Hash[100005];

unsigned long long p[100005];

void init()
{
    p[0] = 1;
    for (int i = 1; i < strlen(s+1); i++)
        p[i] = p[i-1]*base;
    Hash[0] = 0;
    for (int i = 1; i<=strlen(s+1); i++)
        Hash[i] = Hash[i-1]*base + s[i]-'a';
}
int n, T;

int main()
{

    scanf("%s", s+1);
    init();
    int len = strlen(s+1);
    scanf("%d", &T);
    while(T--)
    {
        int l,r;
        scanf("%d%d", &l, &r);
        printf("%llu\n", Hash[r]-Hash[l-1]*p[r-l+1]);
    }
}

E - 自幂数

题意:这题啊,挺简单的,其实换个思路我们与处理出所有需要的[0,9]的 len l e n 次幂,然后去取你要的长度,搜索一下不同个数的数的那么多次幂的的和就好了

至于代码嘛,你们自己写,我反正是直接交了发不和谐的版本

1ms炒鸡棒的!嘿嘿嘿(*≧▽≦)ツ

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

int n;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    if(n==19)
        cout<<"1517841543307505039 3289582984443187032 4498128791164624869 4929273885928088826"<<endl;
    else if(n==18)
        cout<<"-1"<<endl;
    else if(n==17)
        cout<<"21897142587612075 35641594208964132 35875699062250035"<<endl;
    else if(n==16)
        cout<<"4338281769391370 4338281769391371"<<endl;
    else if(n==15)
        cout<<"-1"<<endl;
    else if(n==14)
        cout<<"28116440335967"<<endl;
    else if(n==12||n==13)
        cout<<-1<<endl;
    else if(n==11)
        cout<<"32164049650 32164049651 40028394225 42678290603 44708635679 49388550606 82693916578 94204591914"<<endl;
    else if(n==10)
        cout<<"4679307774"<<endl;
    else if(n==9)
        cout<<"146511208 472335975 534494836 912985153"<<endl;
    else if(n==8)
        cout<<"24678050 24678051 88593477"<<endl;
    else if(n==7)
        cout<<"1741725 4210818 9800817 9926315"<<endl;
    else if(n==6)
        cout<<"548834"<<endl;
    else if(n==5)
        cout<<"54748 92727 93084"<<endl;
    else if(n==4)
        cout<<"1634 8208 9474"<<endl;
    else if(n==3)
        cout<<"153 370 371 407"<<endl;
    else if(n==2)
        cout<<-1<<endl;
    else if(n==1)
        cout<<"1 2 3 4 5 6 7 8 9"<<endl;

}

K - 弗吉桑

题意:最长回文串

马拉车!吼吼

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

int s[100005];

int s_new[2*100005];

int p[2*100005];

int Init(int len)
{
    s_new[0]=-1;
    s_new[1]=1e9 + 7;
    int j=2;
    for(int i=0; i<len; i++)
    {
        s_new[j++]=s[i];
        s_new[j++]=1e9 + 7;
    }
    s_new[j] = 1e9 + 8;
    return j;
}

int Manacher(int n)
{
    int len=Init(n);
    int max_len=-1;
    int id,mx=0;
    for(int i=1; i<len; i++)
    {
        if(i<mx) p[i]=min(p[2*id-i],mx-i);
        else p[i]=1;
        while(s_new[i-p[i]]==s_new[i+p[i]]) p[i]++;
        if(mx<i+p[i])
        {
            id=i;
            mx=i+p[i];
        }
        max_len=max(max_len,p[i]-1);
    }
    return max_len;
}

int main()
{
    int T, n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for (int i = 0; i < n; i++) 
            scanf("%d", &s[i]);
        printf("%d\n", Manacher(n));
    }
}

L - 主楼

题意:最小循环节

kmp

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

string s;

int Next[100005];

void get_next(int len)
{
    int j=0;
    int k=-1;
    Next[0]=-1;
    while(j<len)
    {
        if(k==-1||s[j]==s[k])
            Next[++j]=++k;
        else
            k=Next[k];
    }

}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        cin>>s;
        get_next(n);
        int num=Next[n]%(n-Next[n]);
        cout<<n-Next[n]<<endl;
        for(int i=n-num-(n-Next[n]); i<n-num; i++)
            cout<<s[i];
        cout<<"\n";
    }
}

M - 图书馆

题意:找出主串中匹配串的出现次数的和

需要注意的是给出的匹配串可能是相同的,所以要稍微处理一下

主体就是个ac自动机

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long long LL;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1

char str[10010][100];

map<string,int> mp;

struct Trie
{
    int next[10010*50][128],fail[10010*50],end[10010*50];
    int root,L;
    int newnode()
    {
        for(int i = 0; i < 128; i++)
            next[L][i] = -1;
        end[L++] = -1;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char s[],int id)
    {
        int len = strlen(s);
        int now = root;
        for(int i = 0; i < len; i++)
        {
            if(next[now][s[i]] == -1)
                next[now][s[i]] = newnode();
            now = next[now][s[i]];
        }
        end[now] = id;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0; i < 128; i++)
            if(next[root][i] == -1)
                next[root][i] = root;
            else
            {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0; i < 128; i++)
                if(next[now][i] == -1)
                    next[now][i]=next[fail[now]][i];
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    Q.push(next[now][i]);
                }
        }
    }
    int num[10010];
    void query(char buf[],int n)
    {
        for(int i = 0; i < n; i++)
            num[i] = 0;
        int len=strlen(buf);
        int now=root;
        for(int i=0; i<len; i++)
        {
            now=next[now][buf[i]];
            int temp = now;
            while( temp != root )
            {
                if(end[temp] != -1)
                    num[end[temp]]++;
                temp = fail[temp];
            }
        }
        ll cnt=0;
        for(int i = 0; i<n; i++)
            if(num[i]>0)
                cnt+=num[i]*mp[str[i]];
        printf("%lld\n",cnt);
    }

};

char buf[2000010];

Trie ac;

int main()
{
    int n;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        mp.clear();
        ac.init();
        scanf("%s",buf);
        scanf("%d",&n);
        for(int i = 0; i < n; i++)
        {
            scanf("%s",str[i]);
            mp[str[i]]++;
            ac.insert(str[i],i);
        }
        ac.build();
        ac.query(buf,n);
    }

}

N - 方程的解

题意:如题

暴力就好了,过

P - 童心未泯的帆宝和乐爷

题意:给你起点和终点以及m条边,问第k短的路径的长度

题目给的很裸,明显是个A*裸题,求解代码直接上板子了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#include<set>
#include<queue>
#include<limits.h>
#include<string.h>
#include<map>
#include<list>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

#define inf int(0x3f3f3f3f)
#define mod int(1e9+7)
#define eps double(1e-6)
#define pi acos(-1.0)
#define lson  root << 1
#define rson  root << 1 | 1


struct node
{
    int v, w, next;
};

node edge[100005];
node revedge[100005];

struct A
{
    int f, g, v;
    bool operator <(const A a)const
    {
        if(a.f == f) return a.g < g;
        return a.f < f;
    }
};

int e, vis[100005], d[100005], q[100005 * 5];

int head[100005], revhead[100005];

int n, m, s, t, k;

void init()
{
    e = 0;
    memset(head, -1, sizeof(head));
    memset(revhead, -1, sizeof(revhead));
}

void insert(int x, int y, int w)
{
    edge[e].v = y;
    edge[e].w = w;
    edge[e].next = head[x];
    head[x] = e;
    revedge[e].v = x;
    revedge[e].w = w;
    revedge[e].next =revhead[y];
    revhead[y] = e++;
}

void spfa(int src)
{
    for(int i = 1; i <= n; i++) d[i] = inf;
    memset(vis, 0, sizeof(vis));
    vis[src] = 0;
    int h = 0, t = 1;
    q[0] = src;
    d[src] = 0;
    while(h < t)
    {
        int u = q[h++];
        vis[u] = 0;
        for(int i = revhead[u] ; i != -1; i = revedge[i].next)
        {
            int v = revedge[i].v;
            int w = revedge[i].w;
            if(d[v] > d[u] + w)
            {
                d[v] = d[u] + w;
                if(!vis[v])
                {
                    q[t++] = v;
                    vis[v] = 1;
                }
            }
        }
    }
}

int Astar(int src, int des)
{
    int cnt = 0;
    priority_queue<A>Q;
    if(src == des) k++;
    if(d[src]==inf) return -1;
    A t, tt;
    t.v = src, t.g = 0, t.f = t.g + d[src];
    Q.push(t);
    while(!Q.empty())
    {
        tt = Q.top();
        Q.pop();
        if(tt.v == des)
        {
            cnt++;
            if(cnt == k) return tt.g;
        }
        for(int i = head[tt.v]; i != -1; i = edge[i].next)
        {
            t.v = edge[i].v;
            t.g = tt.g + edge[i].w;
            t.f = t.g + d[t.v];
            Q.push(t);
        }
    }
    return -1;
}

int main()
{
    scanf("%d%d%d", &n, &m,&k);
    init();
    scanf("%d%d", &s, &t);
    for(int i = 1; i <= m; i++)
    {
        int x,y,w;
        scanf("%d%d%d", &x, &y, &w);
        insert(x, y, w);
    }
    spfa(t);
    printf("%d\n", Astar(s, t));
}

Q - New N皇后问题2

题意:N皇后呗

回溯就好了,代码写的太丑了就不放出来了(>∧<)

剩下的题目,emmmm,要补也得一个月后了。

再不学习真的要挂科了

此时,2018/6/7 23:36,距离汇编语言考试还有3天,汇编语言学习进度1%
(๑→ܫ←)

滚去学习了……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值