10.5 考试 (感觉比较难)

T1

正解是 建26颗线段树,但是他们有人被卡常了...

还是分块大法好,跑的最快

直接记录下每一个块 26个字母出现次数,再打上升序还是降序的标记

毕竟考试调了两个小时呢23333

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define dd double
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
inline char readchar()
{
    char q=getchar();
    while(q<'a'||q>'z')q=getchar();
    return q;
}
inline int read()
{
    char q=getchar();int ans=0;
    while(q<'0'||q>'9')q=getchar();
    while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
    return ans;
}
const int N=100006;

int n,m,fen;
int s[N];

int dui[N],L[1006],R[1006],len[1006];
int num[1006][36],flag[1006];

int t[36];

inline void pushdown(int x)
{
    if(flag[x]==-1)
        return ;
    int now;
    if(flag[x]==1)
    {
        now=L[x];
        for(int i=0;i<26;++i)
            while(num[x][i])
                s[now++]=i,--num[x][i];
    }
    else
    {
        now=R[x];
        for(int i=0;i<26;++i)
            while(num[x][i])
                s[now--]=i,--num[x][i];
    }
    flag[x]=-1;
}

inline void pushup(int x)
{
    mem(num[x],0);
    for(int i=L[x];i<=R[x];++i)
        ++num[x][s[i]];
}

inline void get_sum(int l,int r)
{
    int q1=min(r,R[dui[l]]);
    pushdown(dui[l]);
    for(int i=l;i<=q1;++i)
        ++t[s[i]];
    if(dui[l]!=dui[r])
    {
        pushdown(dui[r]);
        for(int i=L[dui[r]];i<=r;++i)
            ++t[s[i]];
    }
    for(int i=dui[l]+1;i<dui[r];++i)
        for(int j=0;j<26;++j)
            t[j]+=num[i][j];
}

inline void changesh(int l,int r)
{
    get_sum(l,r);
    int q1=min(r,R[dui[l]]),now1,now2,temp;
    now1=0;
    now2=l;
    while(now2<=q1)
    {
        while(!t[now1])
            ++now1;
        s[now2]=now1;
        ++now2;
        --t[now1];
    }
    pushup(dui[l]);
    for(int i=dui[l]+1;i<dui[r];++i)
    {
        flag[i]=1;
        mem(num[i],0);
        now2=0;
        while(now2<len[i])
        {
            while(!t[now1])
                ++now1;
            temp=min(len[i]-now2,t[now1]);
            num[i][now1]+=temp;
            now2+=temp;
            t[now1]-=temp;
        }
    }
    if(dui[l]!=dui[r])
    {
        now2=L[dui[r]];
        while(now2<=r)
        {
            while(!t[now1])
                ++now1;
            s[now2]=now1;
            ++now2;
            --t[now1];
        }
        pushup(dui[r]);
    }
}

inline void changexi(int l,int r)
{
    get_sum(l,r);
    int q1=max(l,L[dui[r]]),now1,now2,temp;
    now1=0;

    now2=r;
    while(now2>=q1)
    {
        while(!t[now1])
            ++now1;
        s[now2]=now1;
        --now2;
        --t[now1];
    }
    pushup(dui[r]);
    for(int i=dui[r]-1;i>dui[l];--i)
    {
        flag[i]=0;
        for(int j=0;j<26;++j)num[i][j]=0;
        now2=0;
        while(now2<len[i])
        {
            while(!t[now1])
                ++now1;
            temp=(len[i]-now2<t[now1]?len[i]-now2:t[now1]);
            num[i][now1]+=temp;
            now2+=temp;
            t[now1]-=temp;
        }
    }
    if(dui[l]!=dui[r])
    {
        now2=R[dui[l]];
        while(now2>=l)
        {
            while(!t[now1])
                ++now1;
            s[now2]=now1;
            --now2;
            --t[now1];
        }
        pushup(dui[l]);
    }
}

inline void out11()
{
    for(int i=1;i<=dui[n];++i)
        pushdown(i);
    for(int i=1;i<=n;++i)
        printf("%c",s[i]+'a');
}

int main(){

    //freopen("T1.in","r",stdin);
    //freopen("T1.out","w",stdout);

    mem(flag,-1);

    n=read();m=read();
    //fen=(int)ceil(sqrt((dd)n*13.5+0.5));
    fen=(int)ceil(sqrt(n+0.5));
    for(int i=1;i<=n;++i)
    {
        s[i]=readchar()-'a';
        dui[i]=(i-1)/fen+1;
        ++num[dui[i]][s[i]];
    }
    for(int i=1;i<=dui[n];++i)
    {
        L[i]=(i-1)*fen+1;
        R[i]=min(n,i*fen);
        len[i]=R[i]-L[i]+1;
    }
    int op,l0,r0,now;
    for(int i=1;i<=m;++i)
    {
        l0=read();r0=read();op=read();
        if(l0>r0)
            swap(l0,r0);
        if(op==1)
            changesh(l0,r0);
        else
            changexi(l0,r0);
    }
    out11();
}]
T1

 

T2

考试执着的认为是 容斥,也想过dp,但是觉得就是...(容斥个??)

f[i][j] 前i列中选了j列右区间的方案数

考虑 第i列选右区间还是不选 再考虑左区间选的方案数,用排列计算

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=3006;
const int mod=998244353;

ll jie[N],jieni[N],ni[N];

void chu()
{
    ni[1]=1;
    for(int i=2;i<N;++i)
        ni[i]=(ll)(mod-mod/i)*ni[mod%i]%mod;
    jie[0]=jieni[0]=1;
    for(int i=1;i<N;++i)
    {
        jie[i]=jie[i-1]*i%mod;
        jieni[i]=jieni[i-1]*ni[i]%mod;
    }
}

inline ll A(int n,int m)
{
    if(n<m)
        return 0;
    return jie[n]*jieni[n-m]%mod;
}

int n,m;
int l[N],r[N];
ll f[N][N];

int jil[N],prel[N],jir[N],prer[N];

void dp()
{
    f[0][0]=1;
    for(int i=1;i<=m;++i)
        for(int j=0;j<=n;++j)
        {
            f[i][j]=(f[i][j]+f[i-1][j])%mod;
            if(j>0&&prer[i]-(j-1)>=0)
            //if(j>0)
            {
                //printf("i=%d j=%d\n",i,j);
                f[i][j]=(f[i][j]+f[i-1][j-1]*(prer[i]-(j-1))%mod )%mod;
            }
            if(jil[i])
            {
                if(j+prel[i]>i)
                    f[i][j]=0;
                else
                    f[i][j]=f[i][j]*A(i-j-prel[i-1],jil[i])%mod;
            }
        }
}

int main(){
    
    //freopen("in.in","r",stdin);

    chu();

    scanf("%d%d",&n,&m);
    //printf("n=%d\n",n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&l[i],&r[i]);
        ++jil[l[i]];
        ++jir[r[i]];
    }
    for(int j=1;j<=m;++j)
    {
        prel[j]=prel[j-1]+jil[j];
        prer[j]=prer[j-1]+jir[j];
    }
    dp();
    /*printf("\n");
    for(int i=1;i<=m;++i)
    {
        for(int j=1;j<=n;++j)
            printf("%lld ",f[i][j]);
        printf("\n");
    }*/
    cout<<f[m][n];
}
T2

 

T3

对手的变换其实是把 x循环左移一位...

而x异或一部分数后再左移,相当于x先左移,前i个数异或和再左移

之后就是:

给m+1个数,选一个x,使得x与m+1个数异或和最小值最大

这个可以把m+1个数建一颗0/1trie

然后在树上走

如果这个节点0/1儿子都有,你肯定得选1/0是最后这一位异或是0 (你要保证最小值)

如果只有一个儿子,这一位你要选一个数 使其最后异或是1 (最大值)

之后在得到的m+1个数里 找到ans

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int M=100006;
struct son
{
    son* ch[2];
    son()
    {
        ch[0]=ch[1]=NULL;
    }
}*root;

int n,m,maxp;
int a[M],pre[M];

int con;
int b[M];

void add(int x)
{
    int temp;
    son *now=root;
    for(int i=n-1;i>=0;--i)
    {
        temp=0;
        if( (1<<i)&x )
            temp=1;
        if(now->ch[temp]==NULL)
            now->ch[temp]=new son();
        now=now->ch[temp];
    }
}

inline int move(int x)
{
    return ((1<<(n-1))&x)?(((x<<1)&maxp)|1):((x<<1)&maxp);
}

inline int move2(int x)
{
    return (1&x)?((x>>1)|(1<<(n-1))):(x>>1);
}

void dfs(son *x,int h,int now)
{
    //printf("h=%d now=%d\n",h,now);
    if(h==-1)
    {
        b[++con]=now;
        return ;
    }
    if(x->ch[0]!=NULL&&x->ch[1]!=NULL)
    {
        dfs(x->ch[0],h-1,now);
        dfs(x->ch[1],h-1,now);
    }
    else
        if(x->ch[0]!=NULL)
            dfs(x->ch[0],h-1,now|(1<<h));
    else
        if(x->ch[1]!=NULL)
            dfs(x->ch[1],h-1,now|(1<<h));
    return ;
}

void out11()
{
    printf("%d %d %d\n",move(1),move(2),move(3));
    printf("\n");
    for(int i=1;i<=m;++i)
        printf("%d ",pre[i]);
    printf("\n");
    for(int i=1;i<=con;++i)
        printf("%d ",b[i]);
    printf("\n");
}

int main(){

    //freopen("in.in","r",stdin);
    //freopen("big2.in","r",stdin);

    scanf("%d%d",&n,&m);
    maxp=(1<<n)-1;
    for(int i=1;i<=m;++i)
    {
        scanf("%d",&a[i]);
        pre[i]=pre[i-1]^a[i];
    }
    b[++con]=pre[m];
    for(int i=1;i<=m;++i)
        b[++con]=move(pre[i])^(pre[m]^pre[i]);

    root=new son();
    for(int i=1;i<=con;++i)
        add(b[i]);
    con=0;
    dfs(root,n-1,0);
    int mx=-1,num=0;
    for(int i=1;i<=con;++i)
    {
        if(mx<b[i])
        {
            mx=b[i];
            num=1;
        }
        else
            if(mx==b[i])
                ++num;
    }
    //out11();
    printf("%d\n%d",mx,num);
}
T3

 

这次考试个人觉得比较难

第一题调的时间太长,代码能力有待提升....

 

posted @ 2017-10-06 11:26  A_LEAF  阅读(170)  评论(0编辑  收藏  举报