10.5 考试 (感觉比较难)
Posted A_LEAF
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(); }]
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]; }
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); }
这次考试个人觉得比较难
第一题调的时间太长,代码能力有待提升....
以上是关于10.5 考试 (感觉比较难)的主要内容,如果未能解决你的问题,请参考以下文章