算法学社 -- "这是一道难题"第一期

算法学社 -- "这是一道难题"第一期

针对算法学社新生的一套有奖答题,共9题,分为三个系列,系列内三题的数据难度依次递增。

比赛地址

A、B、C 爱喝醋系列

题解:

一道典型的线段数题,只要建立一个根节点值都是1的线段数,进行区间更新操作,最后输出根节点值就行了。

#include <bits/stdc++.h>
#define N 112345
using namespace std;
#define root 1 , n , 1
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

int n,m;
int sum[N<<2],add1[N<<2];
void pushUp(int rt)
{
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void pushDown1(int l,int r,int rt)
{
    if(add1[rt])
    {
        int m = (l+r)>>1;
        add1[rt<<1] = add1[rt<<1|1] = add1[rt];
        sum[rt<<1] = (m-l+1)*add1[rt];
        sum[rt<<1|1] = (r-m)*add1[rt];
        add1[rt] = 0;
    }
}
void update1(int l,int r,int rt,int ql,int qr,int val)
{
    if(l>qr||ql>r)return;
    if(l>=ql&&r<=qr)
    {
        sum[rt] = (r-l+1)*val;
        add1[rt] = val;
        return;
    }
    pushDown1(l,r,rt);
    int m = (l+r)>>1;
    if(ql<=m)update1(lson,ql,qr,val);
    if(qr>m)update1(rson,ql,qr,val);
    pushUp(rt);
}
void build(int l,int r,int rt)
{
    add1[rt]=0;
    if(l == r)
    {
        sum[rt]=1;
        return;
    }
    int m = (l+r)>>1;
    build(lson);
    build(rson);
    pushUp(rt);
}
int query(int l,int r,int rt,int ql,int qr)
{
    if(l>qr||ql>r)
        return 0;
    if(l>=ql&&r<=qr)
        return sum[rt];
    pushDown1(l,r,rt);
    int m = l+r>>1;
    return query(l,m,rt<<1,ql,qr)+query(m+1,r,rt<<1|1,ql,qr);
}
int main()
{
    int i,j,k,kk,cas,T,t,x,y,z;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        build(root);
        for(i=0;i<m;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            update1(root,x,y,z);
        }
        printf("%d\n",query(root,1,n));
    }
    return 0;
}


D、E、F 斐波那契额系列


题解:

就是一个模拟计算的过程,注意在F题数据上限为1000,整数型无法存下第1000个斐波那契数,所以要用java大数类或者c++写大数加法。

#include <bits/stdc++.h>
#define N 1123
using namespace std;
int n,m;
char ans[N][N];
char * bigAdd(char str1[], char str2[])
{
    char *temp;
    int i, j, tmp, cp=0;
    int l1 = strlen(str1);
    int l2 = strlen(str2);
    if(l1<l2){l1^=l2;l2^=l1;l1^=l2;temp=str2;str2=str1;str1=temp;}

    for(i=l1-1,j=l2-1;i>=0&&j>=0;i--,j--)
    {
        tmp = str1[i]-'0' + str2[j]-'0' +cp;
        str1[i] = tmp%10+'0', cp = tmp/10;
    }
    while(cp)
    {
        if(i<0)
        {
            for(j=l1;j>=0;j--)
                str1[j+1]=str1[j];
            str1[0] = cp+'0';
            cp=0;
        }
        else
            tmp = str1[i]-'0'+cp, str1[i] = tmp%10+'0', cp = tmp/10, i--;
    }
    return str1;
}
char str1[N]="0", str2[N]="1";
void init()
{
    strcpy(ans[1],str2);
    strcpy(ans[0],str1);
    for(int i=2;i<=1000;i++)
    {
        strcpy(str1,ans[i-1]);
        strcpy(str2,ans[i-2]);
        bigAdd(str1,str2);
        strcpy(ans[i],str1);
    }
}
int main()
{
    int i,j,k,kk,cas,T,t,x,y,z;
    init();
    while(scanf("%d",&n)!=EOF)
    {
        printf("%s\n",ans[n]);
    }
    return 0;
}



G、H、I 扫描病毒系列


题解:

就是一个字符串搜索,G完全可以暴力一个字母一个字母对比,H可以用kmp,I可以用AC自动机

#include <bits/stdc++.h>
#define N 112345
using namespace std;
#define N 500010
#define M 128
#define ZIFU 26
char str[N][M];
int num[N],n,m;
struct Trie
{
    int next[N][ZIFU],fail[N],ends[N];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < ZIFU;i++)
            next[L][i] = -1;
        ends[L++] = -1;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void inserts(char s[],int id)
    {
        int len = strlen(s);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][s[i]-'a'] == -1)
                next[now][s[i]-'a'] = newnode();
            now = next[now][s[i]-'a'];
        }
        if(ends[now]!=-1)num[id]=0;
        else ends[now] = id;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < ZIFU;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 < ZIFU;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 query(char buf[])
    {
        int sum=0;
        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]-'a'];
            int temp = now;
            while( temp != root )
            {
                if(ends[temp] != -1)
                    num[ends[temp]]++,sum++;
                temp = fail[temp];
            }
        }
        return sum;
    }

};
char buf[2*N];
Trie ac;
int main()
{
    int i,j,k,kk,cas,T,t,x,y,z;
    while(scanf("%d",&n)!=EOF&&n)
    {
        ac.init();
        for(int i=0;i<n;i++)
        {
            scanf("%s",&str[i]);
            ac.inserts(str[i],i);
        }
        ac.build();
        scanf("%s",&buf);
        ac.query(buf);
        int res=0,ans=-1;
        for(i=0;i<n;i++)
            if(num[i]>res)res=num[i],ans=i;
        if(ans==-1)printf("oh\n");
        else printf("%s %d\n",str[ans],res);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值