7.25题解
两道水题,都贼惨,难受。。。。。。。一大把伤心往事以及蒟蒻的自己,今天上午的我,绝对像个zz
T1
emm,KMP,hash任您挑选,当然我忘了KMP怎么玩,就去打了hash,就这想式子还想了半天,不过点和长度之间的转换最后还是被我玩死了,没倒腾对,不过我最后还是hash过的,hash的话就O(n)长度扫一遍就行了,完全可以作为hash模板题,还是我废物啊,别的就没啥可说的了,注意一下小的细节就可以了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 using namespace std; 6 #define maxn 200010 7 #define ll long long 8 #define ull unsigned long long 9 int t; 10 const ll p=131; 11 char s[maxn],c[2]; 12 int la,lb; 13 ull zhia[maxn],zhib[maxn],jc[maxn]; 14 int check(int cd) 15 { 16 if(!cd) return 1; 17 if(zhia[cd]==(zhib[lb]-zhib[lb-cd]*jc[cd])) return 1; 18 return 0; 19 } 20 int ef(int head,int tail) 21 { 22 if(head==tail) return head; 23 if(head+1==tail) return check(tail)?tail:head; 24 int mid=(head+tail)/2; 25 if(check(mid))return ef(mid,tail); 26 else return ef(head,mid-1); 27 } 28 int main() 29 { 30 scanf("%d",&t); 31 jc[0]=1; jc[1]=p; 32 for(int i=2;i<maxn;++i) jc[i]=jc[i-1]*p; 33 while(t--) 34 { 35 memset(zhia,0,sizeof(zhia)); 36 memset(zhib,0,sizeof(zhib)); 37 scanf("%d%d",&la,&lb); 38 scanf("%s",s); 39 int ls; 40 for(int i=1;i<=la;++i) 41 { 42 ls=s[i-1]-'a'+1; 43 zhia[i]=zhia[i-1]*p+ls; 44 if(i<=lb) zhib[i]=zhib[i-1]*p+ls; 45 } 46 scanf("%s",c); 47 lb++; 48 ls=c[0]-'a'+1; 49 zhib[lb]=zhib[lb-1]*p+ls; 50 int ans=0; 51 for(int i=1;i<=min(la,lb);++i) 52 if(zhia[i]==(zhib[lb]-zhib[lb-i]*jc[i])) ans=i; 53 cout<<ans<<endl; 54 } 55 return 0; 56 }
T2
好好读题,多画样例,仔细思考,别跟我似的,想着啥是啥,打完就扔,我是废物,太废物了,这道题,乍一看给你一种打板子求割点就是正解的错觉,事实上坑还是在的,就是从1到n的必经点肯定是割点,但不见得割点就是必经点,因为有可能从1到n某些割点根本就不需要经过,所以这题你给他点双缩点,然后dfs从1跑到n,标记一下途中经过的割点,那些割点就是最终答案了,记得数组稍微开大一点,记请缩点前后的对应关系就没问题了
1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 #include<stack> 5 #include<cstring> 6 #define maxn 200100 7 #define maxm 400100 8 using namespace std; 9 int T,n,m,js,root,tot,cnt,num,j,ans; 10 int head[maxn],to[maxm*2],xia[maxm*2]; 11 int dfn[maxn],low[maxn],cut[maxn]; 12 int bh[maxn],ss[maxn]; 13 int h[maxn*2],t[maxm*2],x[maxm*2]; 14 int pd[maxn*2],ys[maxn*2]; 15 vector <int> ds[maxn*2]; 16 stack <int> s; 17 void clear() 18 { 19 js=0; root=0; tot=0; num=0; j=0; ans=0; 20 while(s.empty()==false) s.pop(); 21 for(int i=1;i<=cnt;++i) ds[i].clear(); 22 memset(head,0,sizeof(head)); memset(to,0,sizeof(to)); 23 memset(xia,0,sizeof(xia)); memset(dfn,0,sizeof(dfn)); 24 memset(low,0,sizeof(low)); memset(cut,0,sizeof(cut)); 25 memset(bh,0,sizeof(bh)); memset(ss,0,sizeof(ss)); 26 memset(h,0,sizeof(h)); memset(t,0,sizeof(t)); memset(x,0,sizeof(x)); 27 memset(pd,0,sizeof(pd)); memset(ys,0,sizeof(ys)); 28 cnt=0; 29 } 30 void add(int x,int y) 31 { 32 to[++js]=y; xia[js]=head[x]; head[x]=js; 33 } 34 void tarjan(int x) 35 { 36 int bj=0; dfn[x]=low[x]=++tot; s.push(x); 37 if(x==root&&head[x]==0) {ds[++cnt].push_back(x); return ;} 38 for(int i=head[x];i;i=xia[i]) 39 { 40 int ls=to[i]; 41 if(dfn[ls]==0) 42 { 43 tarjan(ls); low[x]=min(low[x],low[ls]); 44 if(low[ls]>=dfn[x]) 45 { 46 bj++; 47 if(x!=root||bj>=2) cut[x]=1; 48 int y; cnt++; 49 do {y=s.top(); s.pop(); ds[cnt].push_back(y);} 50 while(y!=ls); 51 ds[cnt].push_back(x); 52 } 53 } 54 else low[x]=min(low[x],dfn[ls]); 55 } 56 } 57 void ADD(int a,int b) 58 { 59 t[++j]=b; x[j]=h[a]; h[a]=j; 60 } 61 void dfs(int w) 62 { 63 ys[w]=1; 64 if(pd[w]==1) return ; 65 for(int i=h[w];i;i=x[i]) 66 { 67 int ls=t[i]; 68 if(ys[ls]==0) 69 { 70 dfs(ls); 71 if(pd[ls]==1) pd[w]=1; 72 } 73 } 74 } 75 int main() 76 { 77 scanf("%d",&T); 78 while(T--) 79 { 80 scanf("%d%d",&n,&m); 81 for(int i=1;i<=m;++i) 82 { 83 int u,v; scanf("%d%d",&u,&v); 84 add(u,v); add(v,u); 85 } 86 for(int i=1;i<=n;++i) 87 if(dfn[i]==0) {root=i; tarjan(i);} 88 num=cnt; 89 for(int i=1;i<=n;++i) 90 if(cut[i]==1) bh[i]=++num; 91 for(int i=1;i<=cnt;++i) 92 for(int j=0;j<ds[i].size();++j) 93 { 94 int ls=ds[i][j]; 95 if(cut[ls]==1) {ADD(i,bh[ls]); ADD(bh[ls],i);} 96 else ss[ls]=i; 97 } 98 if(cut[n]==1) pd[bh[n]]=1; 99 else pd[ss[n]]=1; 100 if(cut[1]==1) dfs(bh[1]); 101 else dfs(ss[1]); 102 for(int i=2;i<n;++i) 103 { 104 int ls; 105 if(cut[i]==1) ls=bh[i]; 106 else ls=ss[i]; 107 if(pd[ls]==1&&cut[i]==1) ans++; 108 } 109 printf("%d\n",ans); 110 for(int i=2;i<n;++i) 111 { 112 int ls; 113 if(cut[i]==1) ls=bh[i]; 114 else ls=ss[i]; 115 if(pd[ls]==1&&cut[i]==1) printf("%d ",i); 116 } 117 puts(""); clear(); 118 } 119 return 0; 120 }
T3
唯一一道不水的题,让我改了两天,什么破情况,昨天晚上真的改到自闭,回到正题
一个环,要求把颜色一样的挪到一起,这种题一般第一步都是,拆环为链变二倍,然后怎么办呢?枚举每个断点,看这么断的最少移动次数,这就O(n)起步了,再加个n什么之类的估计就死翘翘了,这题我没打部分分,就直接上正解了,(sdfz那大佬三分搞到65分,可惜我不会)
我们把$BR$的排列具化成01串,谁0谁1无所谓,我们假设把0留在中间,那么1被挪到两边需要的移动次数应该就是他移动的方向上0的个数,那么我们来想一下怎么移动最优?也就是怎么样能让每个1两边的0最少,当然是以中间的0为不动点咯,那这样的话我们记录一下每个1两边0的个数就可以了,正着倒着扫一下就好了,我们来想一下这一个序列中所有的1一共要移动的次数,$∑(qian[j]-qian[i-1])+∑(hou[j]-hou[i+len])$,来理解一下这个式子,$qian$就是刚才记录的那个前面有几个0,$hou$记录后面有几个(倒着记录),j代表为1的点,$qian[j]$中的$j$为在中间0前面的点,$hou[j]$中的$j$为在中间0后面的点,$i$代表枚举开始的点,$i+len-1$是枚举结束的点,那这个式子就是用前缀和后缀算出中间一部分,现在我们把它拆开就变成了$∑qian[j]-∑qian[i-1]+∑hou[j]-∑[i+len]$,仔细一看,这个$qian[j]$,$hou[j]$的有点前缀和的意思啊,$yes$,就是前缀和,不对,准确来说是前缀和的前缀和以及后缀和的前缀和,那式子都有了,码就完了,虽然我码了很久。。附赠一下我最后推出来的完整的式子
$ans=qh[mid]-qh[i-1]-qian[i-1]*len1+hh[mid+1]-hh[i+len]-hou[mid+1]*len2$
$len1=(mid-i+1)-(qian[mid]-qian[i-1])$
$len2=(i+len-1-(mid+1)+1)-(hou[mid]-hou[i+len])$
我打的应该不太算正解,因为我拿到的正解需要二分,我实在不觉得决策具有单调性,所以放弃了
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #define maxn 1001000 5 #define int long long 6 using namespace std; 7 int t,len,tot,ans; 8 int cun[maxn*2],qian[maxn*2],hou[maxn*2],qh[maxn*2],hh[maxn*2],jl[maxn*2]; 9 char a[maxn]; 10 void clear() 11 { 12 tot=0; ans=200000000000000000; 13 memset(cun,0,sizeof(cun)); memset(qian,0,sizeof(qian)); 14 memset(hou,0,sizeof(hou)); memset(qh,0,sizeof(qh)); 15 memset(hh,0,sizeof(hh)); memset(jl,0,sizeof(jl)); 16 } 17 signed main() 18 { 19 scanf("%lld",&t); 20 while(t--) 21 { 22 clear(); 23 scanf("%s",a+1); len=strlen(a+1); 24 for(int i=1;i<=len;++i) 25 { 26 if(a[i]=='B') cun[i]=1; 27 else {cun[i]=0; tot++;} 28 } 29 for(int i=len+1;i<=2*len;++i) cun[i]=cun[i-len]; 30 int cnt=0; tot*=2; 31 for(int i=1;i<=2*len;++i) 32 { 33 if(cun[i]==0) {cnt++; jl[cnt]=i; qian[i]=cnt; hou[i]=tot-qian[i]+1;} 34 if(cun[i]==1) {qian[i]=cnt; hou[i]=tot-qian[i];} 35 if(cun[i]==0) qh[i]=qh[i-1]; 36 else qh[i]=qh[i-1]+qian[i]; 37 } 38 for(int i=2*len;i>=1;--i) 39 { 40 if(cun[i]==0) hh[i]=hh[i+1]; 41 else hh[i]=hh[i+1]+hou[i]; 42 } 43 for(int i=1;i<=len;++i) 44 { 45 int da=0; 46 int mid=(qian[i+len-1]-qian[i-1])/2+1+qian[i-1]; mid=jl[mid]; 47 da=qh[mid]-qh[i-1]-qian[i-1]*(mid-i+1-qian[mid]+qian[i-1]); 48 da+=hh[mid+1]-hh[i+len]-hou[i+len]*(i+len-mid-1-hou[mid+1]+hou[i+len]); 49 ans=min(ans,da); 50 } 51 printf("%lld\n",ans); 52 } 53 return 0; 54 }