八月开了一个完美的好头倒数加倍快乐加倍
日常看一遍题,觉得都不可做但是暴力分很好拿,于是快乐开始撕烤&暴力。
T1一看40分白送,然后想了想,和之前一道题排序非常想,排序是01串判断位置,思想还是差不多的。
然后我脑子长了锈了死活转不过弯来
看了看T2,手%样例后发现两个区间之间的地方其实是不能放的。
那么每个小区间都可以影响大区间,处理一下每个-1,码完收工。
T3貌似暴力可以骗40分?前缀和之后处理异或即可,用大暴力和暴力对拍。
T1并没有继续从之前堵住的地方绕出来。
然后就结束了。
题解部分
T1:
明显和排序异曲同工,排序是二分查找位置,将其转化成01串,而这道题明显可以看作是26次区间赋值
然后因为常数太鸡儿大被卡掉,然后循环展开可过我估计和T60的我没有什么关系
换一种思路,如果这一整个区间都是一样的,那么我们把它赋成对应的值,这样就避免了遍历整棵树
然后区间查询个数之后区间赋值 我并不会证明复杂度QwQ
某树袋熊双手上下摇摆:这样你在考场上就快乐的拿到了100分(雾)的好成绩
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define reg register 6 #define ls(k) k<<1 7 #define rs(k) k<<1|1 8 using namespace std; 9 int const maxn=1e5+10; 10 struct node{int l,r,lz,w;}t[maxn*4]; 11 int n,m,cnt[27]; 12 char ch[maxn]; 13 void debug(){for(int i=1;i<=26;i++) cout<<i<<" "<<cnt[i]<<endl;} 14 inline void build(int l,int r,int k) 15 { 16 t[k].l=l,t[k].r=r; 17 if(l==r) 18 { 19 t[k].w=ch[l]-'a'+1; 20 return ; 21 } 22 int mid=l+r>>1; 23 build(l,mid,ls(k)); 24 build(mid+1,r,rs(k)); 25 if(t[ls(k)].w==t[rs(k)].w) t[k].w=t[ls(k)].w; 26 } 27 inline void query(int l,int r,int k) 28 { 29 if(l<=t[k].l&&r>=t[k].r&&t[k].w) 30 { 31 cnt[t[k].w]+=t[k].r-t[k].l+1; 32 return ; 33 } 34 if(t[k].w) t[ls(k)].w=t[k].w,t[rs(k)].w=t[k].w; 35 int mid=t[k].l+t[k].r>>1; 36 if(mid>=l) query(l,r,ls(k)); 37 if(mid<r) query(l,r,rs(k)); 38 } 39 inline void add(int l,int r,int k,int pos) 40 { 41 if((l<=t[k].l&&r>=t[k].r)||t[k].w==pos) 42 { 43 t[k].w=pos; 44 return ; 45 } 46 if(t[k].w) t[ls(k)].w=t[k].w,t[rs(k)].w=t[k].w; 47 int mid=t[k].l+t[k].r>>1; 48 if(mid>=l) add(l,r,ls(k),pos); 49 if(mid<r) add(l,r,rs(k),pos); 50 if(t[ls(k)].w==t[rs(k)].w) t[k].w=t[ls(k)].w; 51 else t[k].w=0; 52 } 53 inline void ask(int k) 54 { 55 if(t[k].w) 56 { 57 for(int i=t[k].l;i<=t[k].r;i++) printf("%c",t[k].w+'a'-1); 58 return ; 59 } 60 ask(ls(k));ask(rs(k)); 61 } 62 int main() 63 { 64 scanf("%d%d",&n,&m); 65 scanf("%s",ch+1); 66 build(1,n,1); 67 for(reg int i=1;i<=m;i++) 68 { 69 for(int i=1;i<=26;i++) cnt[i]=0; 70 int opt,l,r; 71 scanf("%d%d%d",&l,&r,&opt); 72 query(l,r,1); 73 //debug(); 74 if(opt) 75 { 76 int tmp=l; 77 for(reg int j=1;j<=26;j++) 78 { 79 if(!cnt[j]) continue; 80 add(tmp,tmp+cnt[j]-1,1,j); 81 tmp+=cnt[j]; 82 } 83 } 84 else 85 { 86 int tmp=l; 87 for(reg int j=26;j>=1;j--) 88 { 89 if(!cnt[j]) continue; 90 add(tmp,tmp+cnt[j]-1,1,j); 91 tmp+=cnt[j]; 92 } 93 } 94 } 95 ask(1); 96 return 0; 97 }
T2:
又是一个神仙dp,%%%Smily考场A掉TQLOTZ
我本来以为是组合数,码出来的**被我考试后脑子hack,天知道我怎么能这么想。
首先读题可以发现这道题和行几乎没有什么关系,然后我们用列转移。
设$ f[i][j] $为到达第 $i$ 列时左侧有$j$个右区间放了,$L$ 为左区间个数前缀和,$R$ 为右区间个数前缀和
当前状态可以从右区间没有放以及放了转移。
即 $f[i][j]=f[i-1][j]+f[i-1][j-1]*(R[i]-j+1)$
再考虑左区间。
我们可以得到,每一个包含在大区间的小区间都使对大区间中可选择的位置减少1个,所以用它来计算左区间贡献。
并不需要担心负数,因为一旦出现负数那么代表状态不合法。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 int const maxn=3010; 7 int const mod=998244353; 8 ll n,m,l[maxn],r[maxn],L[maxn],R[maxn],f[maxn][maxn]; 9 int main() 10 { 11 scanf("%lld%lld",&n,&m); 12 for(int i=1;i<=n;i++) scanf("%lld%lld",&l[i],&r[i]),L[l[i]]++,R[r[i]]++; 13 for(int i=1;i<=m;i++) L[i]+=L[i-1],R[i]+=R[i-1]; 14 f[0][0]=1; 15 for(int i=1;i<=m;i++) 16 { 17 f[i][0]=f[i-1][0]; 18 for(int j=1;j<=i;j++) (f[i][j]+=f[i-1][j]+f[i-1][j-1]*(R[i]-j+1)%mod)%=mod; //右区间 19 for(int k=0;k<=i;k++) 20 for(int j=L[i-1];j<L[i];j++) 21 (f[i][k]*=(i-k-j))%=mod; //左区间 22 } 23 printf("%lld",f[m][n]); 24 }
T3:
可以很明显看出来枚举断点来判断从而骗到40分然后我因为赋值的原因少了24TAT
首先它的柿子是一个类似于逻辑左移的东西,然后对手有m+1种不同的异或方案。
建一棵$01trie$进行$dfs$,因为对手总会尽量使你的最终结果更低,所以有两种情况:
1,如果当前节点有两个儿子,那么无论这一位是什么,对手都能把它异或成0,不考虑贡献向下走
2,只有1个儿子,那么我们选择另一个就可以使这一位有贡献,继续沿着$trie$走
最终到叶子就是答案,可以看到一开始的柿子对答案并没有影响,因为无论如何都能得到所有的数
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<map> 5 using namespace std; 6 int const maxn=1e5+10; 7 int n,m,a[maxn],sum[maxn],yh[maxn],trie[30*maxn][2],tot,imax; 8 map<int,int>mp; 9 void insert(int x) 10 { 11 //cout<<x<<endl; 12 int rt=0; 13 for(int i=1<<(n-1);i>0;i>>=1) 14 { 15 int w=(x&i)?1:0; 16 if(!trie[rt][w]) trie[rt][w]=++tot; 17 rt=trie[rt][w]; 18 //cout<<x<<" "<<w<<" "<<rt<<endl; 19 } 20 //cout<<endl; 21 } 22 void dfs(int x,int i,int now) 23 { 24 //cout<<x<<" "<<i<<" "<<now<<endl; 25 if(i==0) 26 { 27 imax=max(imax,now); 28 mp[now]++; 29 return ; 30 } 31 if(!trie[x][0]&&trie[x][1]) 32 { 33 dfs(trie[x][1],i-1,(now|(1<<i-1))); 34 } 35 if(trie[x][0]&&!trie[x][1]) 36 { 37 dfs(trie[x][0],i-1,(now|(1<<i-1))); 38 } 39 if(trie[x][0]&&trie[x][1]) 40 { 41 dfs(trie[x][0],i-1,now); 42 43 dfs(trie[x][1],i-1,now); 44 } 45 } 46 int main() 47 { 48 //freopen("da.in","r",stdin); 49 //freopen("ans.txt","w",stdout); 50 scanf("%d%d",&n,&m); 51 for(int i=1;i<=m;i++) scanf("%d",&a[i]); 52 for(int i=1;i<=m;i++) sum[i]=sum[i-1]^a[i]; 53 int s=0; 54 for(int i=0;i<=m;i++) 55 { 56 int now=0; 57 a[i]=(2*a[i]/(1<<n)+2*a[i])%(1<<n); 58 s^=a[i]; 59 now=s^sum[m]^sum[i]; 60 insert(now); 61 } 62 dfs(0,n,0); 63 printf("%d\n%d",imax,mp[imax]); 64 }
40+0+16比较玄学分数,暴力打满100是rank7。
看了一下,现在rank51,非常危险的位置。
以前总觉得自己并不差,一次考不好下回可以考回来。
但是连续的排名靠后就暴露了问题。
正解接近但码不出来,暴力总在细节出错,思路明明接近却无法灵活变通。
非常致命。
如果连暴力都打不满,如果考试持续倒数,如果在NOIP就退役,这不是我想要的结果。
目标是停课,然后省队,然后拿政策。
我答应了的事情就要做到。