NOIP模拟测试11「string·matrix·big」

 

打的big出了点小问题,maxx初值我设的0然后少了10分

第二题暴力打炸

第一题剪了一些没用的枝依然40分

总分70

这是一次失败的考试

string

想到和序列那个题很像,但我没做序列,考场回忆学长讲课,打不出来。最后我口胡了一个CDQ分治,大概能减很多枝比如之前5 6 修改,之后4 6修改,那么其实你5 6不用改。

秉承这个思路,我随意打了一个分治,然后依然40分。

题解

我们可以维护每一段区间字母个数,维护一个桶,每次询问先把桶求出来,按照顺序排序时我们可以顺序枚举26个字母,进行区间修改,然后按照逆序反过来枚举就好了。这样把修改操作转化为若干个区间修改。但单单这么做我们会T,维护起来也不好维护,各种懒标记很恶心,我们还需要别的特殊姿势,

    if(tr[p].a) tr[p<<1].a=tr[p].a,tr[p<<1|1].a=tr[p].a;

这样做我们修改和询问就不用递归到儿子节点了,而且这样我们还节省了维护懒标记时间

那么我们思考如何维护

修改时

    if(tr[p].l>=l&&tr[p].r<=r||tr[p].a==x){
        tr[p].a=x;
        return ;
    }

若区间不完全覆盖

    if(tr[p].a) tr[p<<1].a=tr[p].a,tr[p<<1|1].a=tr[p].a,tr[p].a=0;

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 1010101
struct tree{
    ll x,f,a,l,r;
}tr[A];
char s[A];
ll w[A];
ll n,m;
map<ll,char>mp;
void built(ll p,ll l,ll r){
    tr[p].l=l,tr[p].r=r;
    if(l==r){
//        printf("l=%lld s=%lld\n",l,s[l]-'a'+1ll);
        tr[p].a=s[l]-'a'+1;
        return ;
    }
    ll mid=(l+r)>>1;
    built(p<<1,l,mid);
    built(p<<1|1,mid+1,r);
    if(tr[p<<1].a==tr[p<<1|1].a)
        tr[p].a=tr[p<<1].a;
}
void getsum(ll p,ll l,ll r){
//    printf("l=%lld r=%lld l=%lld r=%lld tr[p].a=%lld\n",tr[p].l,tr[p].r,l,r,tr[p].a);
    if(tr[p].l>=l&&tr[p].r<=r&&tr[p].a){
        w[tr[p].a]+=(tr[p].r-tr[p].l+1);
        return ;
    }
    ll mid=(tr[p].l+tr[p].r)>>1;
    if(tr[p].a) tr[p<<1].a=tr[p].a,tr[p<<1|1].a=tr[p].a;
    if(mid>=l)getsum(p<<1,l,r);
    if(mid<r)getsum(p<<1|1,l,r);
}
void change(ll p,ll l,ll r,ll x){
//    printf("l=%lld r=%lld ***\n",l,r);
    if(tr[p].l>=l&&tr[p].r<=r||tr[p].a==x){
        tr[p].a=x;
        return ;
    }
    ll mid=(tr[p].l+tr[p].r)>>1;
//    printf("tr[%lld]=%lld\n",p,tr[p].a);    
    if(tr[p].a) tr[p<<1].a=tr[p].a,tr[p<<1|1].a=tr[p].a,tr[p].a=0;
    if(mid>=l) change(p<<1,l,r,x);
    if(mid<r) change(p<<1|1,l,r,x);
}
void out(ll p){
//    printf("p=%lld tr[p].a=%lld mp=%c\n",p,tr[p].a,mp[tr[p].a]);
    if(tr[p].a){
        for(ll i=1;i<=tr[p].r-tr[p].l+1;i++)
            printf("%c",(char)mp[tr[p].a]);
        return ;
    }
    out(p<<1);
    out(p<<1|1);
}
void pre(){
    for(ll i=1;i<=26;i++)
        mp[i]='a'+i-1;
    return ;
}
int main(){
    pre();
    scanf("%lld%lld",&n,&m);
    scanf("%s",s+1);
    built(1,1,n);
    for(ll i=1,a,b,c,t;i<=m;i++){
        scanf("%lld%lld%lld",&a,&b,&c);    
        getsum(1,a,b);
        ll l=a;
        if(c){
            for(ll t=1;t<=26;t++)
                if(w[t])
                    change(1,l,l+w[t]-1,t),l=l+w[t],w[t]=0;
        }
        else {
            for(ll t=26;t>=1;t--)
                if(w[t])
                    change(1,l,l+w[t]-1,t),l=l+w[t],w[t]=0;
        }
    }
    out(1);
    puts("");
}

big

题解

$40\%$

按照题目说的做,直接枚举

$100\%$

我们建一棵tire树,

代码

#include<bits/stdc++.h>
#define ll long long
#define A 6000000
using namespace std;
ll tire[A][2],t[A],sum[A],dl[A],a[A];
ll tot=1,n,m,maxx=0,ans=0;
bool pan;
ll change(ll x){
    return (2*x/(1<<n)+2*x)%(1<<n);
}
bool cmp(ll x,ll y){
    return x>y;
}
inline void insert(ll x)
{
    ll p=1;
    for(ll i=1;i<=n;i++)
    {
        ll zan=(x>>(n-i))&1;
//        printf("zan=%lld tot=%lld\n",zan,tot);
        if(!tire[p][zan]) tire[p][zan]=++tot;
        p=tire[p][zan];
    }
}
inline ll dfs(ll x,ll zhi,ll deep)
{
    if(deep<0){
        dl[++dl[0]]=zhi;
    }
//    printf("trie[0][1]=[%lld][%lld] deep=%lld zhi=%lld 1<<=%lld\n",tire[x][0],tire[x][1],deep,zhi,1ll<<deep);
    if(tire[x][0]&&!tire[x][1])
        dfs(tire[x][0],zhi^(1ll<<deep),deep-1);
    if(!tire[x][0]&&tire[x][1])
        dfs(tire[x][1],zhi^(1ll<<deep),deep-1);
    if(tire[x][0]&&tire[x][1]){
        dfs(tire[x][0],zhi,deep-1);dfs(tire[x][1],zhi,deep-1);
    }
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=m;i++)
        scanf("%lld",&a[i]);
    for(ll i=m;i>=1;i--)
        sum[i]=sum[i+1]^a[i];
    for(ll i=0,now=0;i<=m;i++){
//        printf("now=%lld  add=%lld\n",now,now^sum[i+1]);
        now=now^change(a[i]);
        insert(now^sum[i+1]);
    }
//    printf("1 %lld 0%lld\n",tire[1][1],tire[1][0]);
    dfs(1,0,n-1);
    sort(dl+1,dl+dl[0]+1,cmp);
    for(ll i=1;i<=dl[0];i++)
    if(dl[i]==dl[1]) ans++;
    printf("%lld\n%lld\n",dl[1],ans);
}

 

转载于:https://www.cnblogs.com/znsbc-13/p/11286426.html

NOI(全国青少年信息学奥林匹克竞赛)模拟赛的测试数据是指用于评测参赛选手的程序的输入和对应的输出。测试数据是非常重要的,因为它决定了参赛选手的程序能否正确地解决问题。 在NOI模拟赛中,测试数据具有以下特点: 1.充分覆盖:测试数据应涵盖各种可能的输入情况,包括边界条件和极端情况。通过提供不同的测试数据,可以考察选手对问题的全面理解和解决能力。 2.随机性和均衡性:为了公平起见,测试数据应该是随机生成的,而不是针对某个特定算法或解法设计的。同时,测试数据应该是均衡的,即各种情况的概率应该大致相等,以避免偏向某些解法。 3.合理性和可行性:测试数据应该是合理和可行的,即符合题目要求的输入数据,并且是选手能够通过编写程序来处理的。测试数据应该考虑到程序的限制和时间复杂度,以充分测试选手的编程能力。 NOI模拟赛的测试数据通常由经验丰富的考题组负责生成。他们会根据题目的要求和限制,设计出一组合理、充分、随机和均衡的测试数据,以确保参赛选手的程序在各种情况下都能正确运行,并且能通过性能测试。 总之,测试数据在NOI模拟赛中起到了至关重要的作用,它既考察了选手对问题的理解和解决能力,又提高了选手编程的技巧和效率。同时,合理和恰当的测试数据也是公平竞赛的保证,确保每个参赛选手有相同的机会和条件进行竞争。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值