20190801考试反思

  这次考试可以说是  极其失败。首先在下午一开始拿到题,头脑不清,夜不能寐,辗转反侧,积劳成疾,胡思乱想。看一眼T1,????学长讲过?我又没做???完了完了,好像是什么二分建树,先打个暴力再说,这个暴力挺好打,打完过样例20min,看T2:?????????方案数??完了图论方案数,心里阴影「奇怪的道路」。先打个暴力再说,dfs一波,打完40min,看T3:????????位运算,异或???手动吃屎。先……打个暴力?枚举一波,打完60min,一看表,好吧开始想正解吧。想了一会200min。。。。收卷。然后获得了出题人有手就送的暴力分。想了两个半小时以后啥也没想出来。。。

  T1:线段树维护桶排序,然后26次赋值。。。手动排序,理论复杂度$O(mlogn)$极其友好,然而可见常数就有$26^{2}$,而且教练不给开氧,于是我们就各种神仙操作,其中最有效的是26次循环展开,代码令人心疼

  

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=100020;
char op[N];
int bin[30];
struct node
{
    int tin[30];
    int &operator [](int x){return tin[x];}
    node operator +(node b)
    {
        node c;c.clear();
        for(int i=0;i<26;i++)
            c[i]=tin[i]+b[i];
        return c;
    }
    void clear(){memset(tin,0,sizeof(tin));}
    void print()
    {
        for(int i=0;i<26;i++)
            printf("%d %d
",i,tin[i]);
        puts("");
    }
};
struct tree{int l,r,w,f;node bin;}tr[N*4];
inline int rd()
{
    int s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
void change(int k,int w)
{
    tr[k].w=(tr[k].r-tr[k].l+1)*w;
    tr[k].f=w;
    tr[k].bin[0]=0;
    tr[k].bin[1]=0;
    tr[k].bin[2]=0;
    tr[k].bin[3]=0;
    tr[k].bin[4]=0;
    tr[k].bin[5]=0;
    tr[k].bin[6]=0;
    tr[k].bin[7]=0;
    tr[k].bin[8]=0;
    tr[k].bin[9]=0;
    tr[k].bin[10]=0;
    tr[k].bin[11]=0;
    tr[k].bin[12]=0;
    tr[k].bin[13]=0;
    tr[k].bin[14]=0;
    tr[k].bin[15]=0;
    tr[k].bin[16]=0;
    tr[k].bin[17]=0;
    tr[k].bin[18]=0;
    tr[k].bin[19]=0;
    tr[k].bin[20]=0;
    tr[k].bin[21]=0;
    tr[k].bin[22]=0;
    tr[k].bin[23]=0;
    tr[k].bin[24]=0;
    tr[k].bin[25]=0;
    tr[k].bin[w]=tr[k].r-tr[k].l+1;
}
void updata(int k)
{
    tr[k].w=tr[k<<1].w+tr[k<<1|1].w;
    tr[k].bin[0]=tr[k<<1].bin[0]+tr[k<<1|1].bin[0];
    tr[k].bin[1]=tr[k<<1].bin[1]+tr[k<<1|1].bin[1];
    tr[k].bin[2]=tr[k<<1].bin[2]+tr[k<<1|1].bin[2];
    tr[k].bin[3]=tr[k<<1].bin[3]+tr[k<<1|1].bin[3];
    tr[k].bin[4]=tr[k<<1].bin[4]+tr[k<<1|1].bin[4];
    tr[k].bin[5]=tr[k<<1].bin[5]+tr[k<<1|1].bin[5];
    tr[k].bin[6]=tr[k<<1].bin[6]+tr[k<<1|1].bin[6];
    tr[k].bin[7]=tr[k<<1].bin[7]+tr[k<<1|1].bin[7];
    tr[k].bin[8]=tr[k<<1].bin[8]+tr[k<<1|1].bin[8];
    tr[k].bin[9]=tr[k<<1].bin[9]+tr[k<<1|1].bin[9];
    tr[k].bin[10]=tr[k<<1].bin[10]+tr[k<<1|1].bin[10];
    tr[k].bin[11]=tr[k<<1].bin[11]+tr[k<<1|1].bin[11];
    tr[k].bin[12]=tr[k<<1].bin[12]+tr[k<<1|1].bin[12];
    tr[k].bin[13]=tr[k<<1].bin[13]+tr[k<<1|1].bin[13];
    tr[k].bin[14]=tr[k<<1].bin[14]+tr[k<<1|1].bin[14];
    tr[k].bin[15]=tr[k<<1].bin[15]+tr[k<<1|1].bin[15];
    tr[k].bin[16]=tr[k<<1].bin[16]+tr[k<<1|1].bin[16];
    tr[k].bin[17]=tr[k<<1].bin[17]+tr[k<<1|1].bin[17];
    tr[k].bin[18]=tr[k<<1].bin[18]+tr[k<<1|1].bin[18];
    tr[k].bin[19]=tr[k<<1].bin[19]+tr[k<<1|1].bin[19];
    tr[k].bin[20]=tr[k<<1].bin[20]+tr[k<<1|1].bin[20];
    tr[k].bin[21]=tr[k<<1].bin[21]+tr[k<<1|1].bin[21];
    tr[k].bin[22]=tr[k<<1].bin[22]+tr[k<<1|1].bin[22];
    tr[k].bin[23]=tr[k<<1].bin[23]+tr[k<<1|1].bin[23];
    tr[k].bin[24]=tr[k<<1].bin[24]+tr[k<<1|1].bin[24];
    tr[k].bin[25]=tr[k<<1].bin[25]+tr[k<<1|1].bin[25];
}
void down(int k)
{
    change(k<<1,tr[k].f);
    change(k<<1|1,tr[k].f);
    tr[k].f=-1;
}
void build(int k,int l,int r)
{
    tr[k].l=l,tr[k].r=r;
    if(l==r){tr[k].w=op[l]-'a';tr[k].bin[tr[k].w]++;return ;}
    int mid=l+r>>1;
    tr[k].f=-1;
    tr[k].bin.clear();
    build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    updata(k);
}
int ask(int k,int id)
{
    int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
    if(l==r) return tr[k].w;
    if(tr[k].f!=-1) down(k);
    if(id<=mid) return ask(k<<1,id);
    else return ask(k<<1|1,id);
}
node query(int k,int x,int y)
{
    int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
    if(l==x&&r==y) return tr[k].bin;
    if(tr[k].f!=-1) down(k);
    if(y<=mid) return query(k<<1,x,y);
    else if(x>mid) return query(k<<1|1,x,y);
    return query(k<<1,x,mid)+query(k<<1|1,mid+1,y);
}
void add(int k,int x,int y,int w)
{
    int l=tr[k].l,r=tr[k].r,mid=l+r>>1;
    if(x==l&&r==y){change(k,w);return ;}
    if(tr[k].f!=-1) down(k);
    if(y<=mid) add(k<<1,x,y,w);
    else if(x>mid) add(k<<1|1,x,y,w);
    else add(k<<1,x,mid,w),add(k<<1|1,mid+1,y,w);
    updata(k);
}
inline void binsort(int l,int r,int x)
{
    node c=query(1,l,r);
    int k=l;
    for(int i=0;i<26;i++)bin[i]=c[i];
    if(x)
    {
    if(bin[0]){add(1,k,k+bin[0]-1,0);k+=bin[0];}
    if(bin[1]){add(1,k,k+bin[1]-1,1);k+=bin[1];}
    if(bin[2]){add(1,k,k+bin[2]-1,2);k+=bin[2];}
    if(bin[3]){add(1,k,k+bin[3]-1,3);k+=bin[3];}
    if(bin[4]){add(1,k,k+bin[4]-1,4);k+=bin[4];}
    if(bin[5]){add(1,k,k+bin[5]-1,5);k+=bin[5];}
    if(bin[6]){add(1,k,k+bin[6]-1,6);k+=bin[6];}
    if(bin[7]){add(1,k,k+bin[7]-1,7);k+=bin[7];}
    if(bin[8]){add(1,k,k+bin[8]-1,8);k+=bin[8];}
    if(bin[9]){add(1,k,k+bin[9]-1,9);k+=bin[9];}
    if(bin[10]){add(1,k,k+bin[10]-1,10);k+=bin[10];}
    if(bin[11]){add(1,k,k+bin[11]-1,11);k+=bin[11];}
    if(bin[12]){add(1,k,k+bin[12]-1,12);k+=bin[12];}
    if(bin[13]){add(1,k,k+bin[13]-1,13);k+=bin[13];}
    if(bin[14]){add(1,k,k+bin[14]-1,14);k+=bin[14];}
    if(bin[15]){add(1,k,k+bin[15]-1,15);k+=bin[15];}
    if(bin[16]){add(1,k,k+bin[16]-1,16);k+=bin[16];}
    if(bin[17]){add(1,k,k+bin[17]-1,17);k+=bin[17];}
    if(bin[18]){add(1,k,k+bin[18]-1,18);k+=bin[18];}
    if(bin[19]){add(1,k,k+bin[19]-1,19);k+=bin[19];}
    if(bin[20]){add(1,k,k+bin[20]-1,20);k+=bin[20];}
    if(bin[21]){add(1,k,k+bin[21]-1,21);k+=bin[21];}
    if(bin[22]){add(1,k,k+bin[22]-1,22);k+=bin[22];}
    if(bin[23]){add(1,k,k+bin[23]-1,23);k+=bin[23];}
    if(bin[24]){add(1,k,k+bin[24]-1,24);k+=bin[24];}
    if(bin[25]){add(1,k,k+bin[25]-1,25);k+=bin[25];}
    }
    else
    {
        if(bin[25]){add(1,k,k+bin[25]-1,25);k+=bin[25];}
        if(bin[24]){add(1,k,k+bin[24]-1,24);k+=bin[24];}
        if(bin[23]){add(1,k,k+bin[23]-1,23);k+=bin[23];}
        if(bin[22]){add(1,k,k+bin[22]-1,22);k+=bin[22];}
        if(bin[21]){add(1,k,k+bin[21]-1,21);k+=bin[21];}
        if(bin[20]){add(1,k,k+bin[20]-1,20);k+=bin[20];}
        if(bin[19]){add(1,k,k+bin[19]-1,19);k+=bin[19];}
        if(bin[18]){add(1,k,k+bin[18]-1,18);k+=bin[18];}
        if(bin[17]){add(1,k,k+bin[17]-1,17);k+=bin[17];}
        if(bin[16]){add(1,k,k+bin[16]-1,16);k+=bin[16];}
        if(bin[15]){add(1,k,k+bin[15]-1,15);k+=bin[15];}
        if(bin[14]){add(1,k,k+bin[14]-1,14);k+=bin[14];}
        if(bin[13]){add(1,k,k+bin[13]-1,13);k+=bin[13];}
        if(bin[12]){add(1,k,k+bin[12]-1,12);k+=bin[12];}
        if(bin[11]){add(1,k,k+bin[11]-1,11);k+=bin[11];}
        if(bin[10]){add(1,k,k+bin[10]-1,10);k+=bin[10];}
        if(bin[9]){add(1,k,k+bin[9]-1,9);k+=bin[9];}
        if(bin[8]){add(1,k,k+bin[8]-1,8);k+=bin[8];}
        if(bin[7]){add(1,k,k+bin[7]-1,7);k+=bin[7];}
        if(bin[6]){add(1,k,k+bin[6]-1,6);k+=bin[6];}
        if(bin[5]){add(1,k,k+bin[5]-1,5);k+=bin[5];}
        if(bin[4]){add(1,k,k+bin[4]-1,4);k+=bin[4];}
        if(bin[3]){add(1,k,k+bin[3]-1,3);k+=bin[3];}
        if(bin[2]){add(1,k,k+bin[2]-1,2);k+=bin[2];}
        if(bin[1]){add(1,k,k+bin[1]-1,1);k+=bin[1];}
        if(bin[0]){add(1,k,k+bin[0]-1,0);k+=bin[0];}
    }
}
int main()
{
    int n=rd(),m=rd();
    scanf("%s",op+1);
    build(1,1,n);
    for(int i=1;i<=m;++i)
    {
        int l=rd(),r=rd(),x=rd();
        binsort(l,r,x);
    }
    for(int i=1;i<=n;++i)
        printf("%c",(char)ask(1,i)+'a');
    puts("");
    return 0;
}
/*
g++ 1.cpp -o 1
./1
5 2
cabcd
1 3 1
3 5 0
*/

  T2:神仙题,状态定义令人发指。。。$f[i][j]$表示前i列有j列已经放入左端点在i以前的右区间,并且i列以前已经结束的左区间以及考虑完毕的方案数。。。。。突然想找到出题人打一顿。。。稍微感性理解一下,再定义几个已知量$l[i]$代表在右端点在1到i列的区间数,$r[i]$表示左端点在1到i列的右区间数,然后就可以得到转移,我还是觉得填表好理解,$r[i]-(j-1)$为目前剩余可填的右区间数,那么就可以知道$f[i][j]=f[i-1][j-1]*(r[i]-j+1)+f[i-1][j]$就是当前列放或不放,当然还得考虑当前左区间,接下来可能比较难以理解,我也搞了好一会,首先左右区间由是用乘法原理应该很能理解,那么就剩左区间的个数了,我的理解是:由于在左区间中长区间不一定会影响短区间(可能放在短区间之外)但短区间一定会影响长区间,所以我从左往右扫就能从短到长,因此直接能求解,然而此时从右区间就是从长到短,所以我要DP求解,那么我们如何求左区间,刚刚说过短的一定影响长的(不要取笑……)我们还是已经处理完短的,那就直接排除影响找到能放的列$i-j-l[i-1]$就是此时能放的列,有$l[i]-l[i-1]$行要放,因此直接搞排列,因为是行列相交的那块,可以yy一下为啥不是组合数,$f[i][j]*=A_{i-j-l[i-1]}^{l[i]-l[i-1]}$,然后注意一下边界,不要有负数之类的,就结束了。

  

#include<iostream>
#include<cstdio>
using namespace std;
const int N=3020,mod=998244353;
int l[N],r[N],f[N][N],fac[N],inv[N];
int rd()
{
    int s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
int qpow(int a,int k)
{
    int ans=1;
    for(;k;k>>=1,a=1ll*a*a%mod) if(k&1) ans=1ll*ans*a%mod;
    return ans;
}
int A(int n,int m)
{
    if(n<0||m<0) return 0;
    if(n<m) return 0;
    if(m==0) return 1;
    return 1ll*fac[n]*inv[n-m]%mod;
}
int main()
{
  //    freopen("data.in","r",stdin);
    //    freopen("data.out","w",stdout);
    int n=rd(),m=rd();fac[0]=1;
    int tm=max(n,m);
    for(int i=1;i<=tm;i++) fac[i]=1ll*fac[i-1]*i%mod;
    inv[tm]=qpow(fac[tm],mod-2);
    for(int i=tm;i;i--) inv[i-1]=1ll*inv[i]*i%mod;
    for(int i=1,x,y;i<=n;i++)
    {
        x=rd(),y=rd();
        l[x]++;r[y]++;
    }
    for(int i=1;i<=m;i++) r[i]+=r[i-1],l[i]+=l[i-1];
    f[0][0]=1;
    for(int i=1;i<=m;i++)
        for(int j=0;j<=n;j++)
        {
            if(j==0) f[i][j]=(f[i][j]+f[i-1][j])%mod;
            else
            {
                if(r[i]-j+1>=0) f[i][j]=(f[i][j]+1ll*f[i-1][j-1]*(r[i]-j+1)%mod+f[i-1][j])%mod;
                else f[i][j]=(f[i][j]+f[i-1][j])%mod;
            }
            f[i][j]=1ll*f[i][j]*A(i-j-l[i-1],l[i]-l[i-1])%mod;
        }
    printf("%d
",f[m][n]);
    return 0;
}
/*
g++ 1.cpp -o 1
./1
2 6
2 4
5 6
*/
View Code

  T3:我不写题解,先给吴神上柱香,四句话给我搞懂了。

  

  

//发现:对手的操作就是把目前数字左移1位,溢出位补到末尾
//转化:对手可以把前1~i个操作都左移1位,溢出同上
//简化:对手一共有m个数,他会选其一来异或你使你尽量小
//问题:选出数使它被m个数中任意一个异或后的得数的最小值尽量大,最大值?方案数?
//求解:0/1-trie,尽量避开对手的m个数。复杂度O(mn)?
#include<cstdio>
int n,m,c[100005],ss,ans=-1,fa,cnt,t[3000005][2];
int ll(int p){return p&1<<n-1?p<<1^1<<n^1:p<<1;}
void insert(int p,int pos){
    for(int i=n-1;~i;--i)
        pos=t[pos][p&1<<i?1:0]?t[pos][p&1<<i?1:0]:(t[pos][p&1<<i?1:0]=++cnt);
}
void dfs(int pos,int aans,int dep){
    if(dep==-1){
        if(aans==ans)fa++;
        if(aans>ans)ans=aans,fa=1;
        return;
    }
    if(t[pos][0]&&t[pos][1])dfs(t[pos][0],aans,dep-1),dfs(t[pos][1],aans,dep-1);
    else if(t[pos][0])dfs(t[pos][0],aans|1<<dep,dep-1);
    else dfs(t[pos][1],aans|1<<dep,dep-1);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)scanf("%d",&c[i]),ss^=c[i];
    for(int i=0;i<=m;++i)ss^=c[i],ss^=ll(c[i]),insert(ss,0);
    dfs(0,0,n-1);
    printf("%d
%d
",ans,fa);
}
View Code

  努力成长

原文地址:https://www.cnblogs.com/starsing/p/11290899.html