暑期集训day3训练(数据结构)

B题
题意:给出n个数,两种操作。
M x y:求区间[x,y]的和
S x r:将x更新为r

思路:线段树

#include <cstdio>
#include <cstring>
#define maxn 200000 + 5

using namespace std;
int c[maxn], a[maxn];
int n,t;
int Lowbit(int x)  // 2^k
{
    return x&(-x);
}
void update(int i, int x)//i点增量为x
{
    while(i <= n)
    {
        c[i] += x;
        i += Lowbit(i);
    }
}
int sum(int x)//区间[1,x]求和
{
    int sum=0;
    while(x>0)
    {
        sum+=c[x];
        x-=Lowbit(x);
    }
    return sum;
}

int Getsum(int x1,int x2) //求任意区间和
{
    return sum(x2) - sum(x1-1);
}
int main()
{
    int cnt = 0, i, j;
    while(~scanf("%d",&n))
    {
        if(n == 0) break;
        cnt++;
        memset(a,0,sizeof(a));
        memset(c,0,sizeof(c));
        for(i = 1; i <= n; i++) //i必须从1开始
        {
            scanf("%d",&a[i]);
            update(i,a[i]);
        }
        if(cnt != 1) printf("\n");
        printf("Case %d:\n",cnt);
        char oper[5];
        while(~scanf("%s",oper))
        {
            if(strcmp(oper,"END")==0){
                break;
            }
            scanf("%d%d",&i,&j);
            if(strcmp(oper,"M")==0)
            {
                if(i == 1) printf("%d\n",sum(j));
                else printf("%d\n",Getsum(i,j));
            }
            if(strcmp(oper,"S")==0)
            {
                update(i,j-a[i]);
                a[i] = j;
            }
        }
    }
    return 0;
}

D题
题意:给出一个字符串str,求出str中存在多少子串,使得这些子串既是str的前缀,又是str的后缀。从小到大依次输出这些子串的长度。

思路:kmp的next数组运用,求出末尾的next值,并递归的向下求出所有的next值。

#include <cstdio>
#include <cstring>

using namespace std;
const int N = 400000 + 5;
int next[N];
char s[N];
int len;
//get next arr
void getNext(char *T)
{
    int j,k;
    int len = strlen(T);
    j = 0;
    k = -1;
    next[0] = -1;
    while(j < len) {
        if(k == -1 || T[j] == T[k])
            next[++j] = ++k;
        else
            k = next[k];
    }
}

void print(int i)
{
    if(next[i] > 0) {
        print(next[i]);
        printf("%d ", next[i]);
    }
}

int main()
{
    while(~scanf("%s",s)) {
        len = strlen(s);
        getNext(s);
        print(len);
        printf("%d\n", len);
    }
    return 0;
}

E题
题意:给出n个数,其中任意三个数si,sj,sk,求(si+sj)^sk最大值。
思路:其实暴力也能过。01字典树。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

const int maxn = 1000 + 10;
const int maxnode = 100000 + 10;

int a[maxn];
int ch[maxnode][2];
int val[maxnode];
int sz,n,t;
void init(){
    sz=1;
    memset(ch[0],0,sizeof(ch[0]));
    memset(val,0,sizeof(val));
}
void add(int x,int v){
    int p = 0;
    for(int i=31;i>=0;i--){
        int id = (x>>i)&1;
        if(ch[p][id]==0){
            memset(ch[sz],0,sizeof(ch[sz]));
            val[sz]=0;
            ch[p][id]=sz++;
        }
        p = ch[p][id];
        val[p]+=v;
    }
}
void Delete(int x)
{
    int u = 0, v;
    for(int i = 31; i >= 0; i--)
    {
        v = (x & (1 << i)) ? 1 : 0;
        u = ch[u][v];
        val[u]--;
    }
}
int Query(int x){
    int ans = 0,u = 0;
    x = ~x;
    for(int i=31;i>=0;i--){
        ans*=2;
        int id = (x>>i)&1;
        if(ch[u][id]&&val[ch[u][id]]){
            ans++;
            u = ch[u][id];
        }
        else
            u = ch[u][1-id];
    }
    return ans;
}

int main()
{
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        init();
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            add(a[i],1);
        }
        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            Delete(a[i]);
            for(int j = i+1; j <= n; j++)
            {
                Delete(a[j]);
                ans = max(ans, Query(a[i]+a[j]));
                add(a[j],1);
            }
            add(a[i],1);
        }
        printf("%d\n",ans);
    }
    return 0;
}

感觉自己有点应付了事了,有心思再修改,剩下的慢慢补吧。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值