高二上一调
【比赛】这次应该叫高二上一调 - 比赛 - 衡中OI (hszxoj.com)
T1:白痴字符串匹配题
就是给你A串,B串,让你找A的前缀和B的后缀最大匹配长度
63
错误原因:
1.hash用了偶数进制,出错率高
2.自然溢出好像出错率也很高
1MB-1024KB-1024*1024B
1B=8字节
T2图论:求割点问题
给你一张无向图,让你求从1--n的必经结点有多少个,不算起点和终点
tarjan的灵活运用
我把割点的概念分割:
对于x的每个子图来说的割点
如果sonx的子图包含n,并且low要>=dfn[x]那么就把他加进去答案
struct node { int to,fr,nxt; }e[N<<3]; int head[N],tot,root; inline void add(int x,int y) { e[++tot].to=y,e[tot].nxt=head[x],head[x]=tot,e[tot].fr=x; } int dfn[N],dfn_cnt,low[N]; int n,m; bool cut[N],is[N]; set<int>ans;//da__>xiao??? //is[x]=1:x是在dfs过程中经过n的 inline void tarjan(int x) { dfn[x]=low[x]=++dfn_cnt;int fl=0; if(x==n) { is[x]=1;//如果到了n,那所有的在ans里的点应该就都处理过了吧 } for(int i=head[x];i;i=e[i].nxt) { int to=e[i].to; if(!dfn[to]) { tarjan(to); if(is[to])is[x]=1; low[x]=min(low[x],low[to]); if(low[to]>=dfn[x]) { fl++; if(root!=x||fl>1) { if(is[to]&&x!=1) { cut[x]=1;//如果to是n的经过的路 ans.insert(x); } } } } else low[x]=min(low[x],dfn[to]); } } void solve() { _f(i,1,n)dfn[i]=low[i]=head[i]=cut[i]=is[i]=0;root=0;tot=0; n=re(),m=re(); ans.clear(); _f(i,1,m) { int u=re(),v=re();add(u,v);add(v,u); } root=1,tarjan(1); set<int>::iterator it; int anse=ans.size(); chu("%d\n",anse); for(it=ans.begin();it!=ans.end();it++) { chu("%d ",*it); } chu("\n"); } int main() { int t=re(); while(t--) { solve(); } return 0; }
T3
给你一个只包含BR的字符环,让你求最少的挪动步数(任意2个可以交换位置)
首先想到拆环为链,枚举所有情况-》
怎么枚举?
1发现如果mid位置的B靠左,那么ST---MID-1一定也要靠左,直接每次枚举起点、断点(20分)
2.枚举的时候预处理每个B前面有多少个R就是它必须走的步数,前缀数组优化
这样枚举之后计算就是O(1)(40分)
3.再考虑枚举答案的单调性:
起点每次向R移动,那么对于每个决策点一定是向L移动的步数减少(左边的步数一定减少)
而且cnt+1的ans,一定是再cnt的ans向右
也就是说用cut记录断点,线性移动一遍,一定可以找到答案
O(n)(100分)
难点:怎么线性的算出有st、cut的ans?
总体前缀和维护和插补思想
维护R B 个数、移动到端点的步数前缀和
对于l--mid的点全部靠左就是:mov[l--mid]-totr[1--l-1]*totb[l--mid]
就是所有B点移动到1,但是我·实际上要移动到l,减去我每个B多移动的
int t; char s[N]; int totrr[N],totlr[N],totrb[N],totlb[N]; ll movl[N],movr[N]; //movl[i]=totlr[i-1] inline ll getans(int st,int ed,int k)//1LL* {//k=st-1,k=0 if(k>ed)return 1e18;//没有实际意义 return 1LL*(movl[k]-movl[st-1]-1LL*(totlb[k]-totlb[st-1])*totlr[st-1]+movr[k+1]-movr[ed+1]-1LL*(totrb[k+1]-totrb[ed+1])*totrr[ed+1]); } int len; void deal() { scanf("%s",s+1); _f(i,1,len) movl[i]=movr[i]=0; len=strlen(s+1); _f(i,len+1,len+len) { s[i]=s[i-len]; } len<<=1; int lstb=0; _f(i,1,len) { if(s[i]=='B') { totlb[i]=totlb[i-1]+1; totlr[i]=totlr[i-1]; movl[i]=1LL*(movl[lstb]+1LL*totlr[i-1]); lstb=i; } else { totlb[i]=totlb[i-1]; totlr[i]=totlr[i-1]+1; movl[i]=movl[i-1]; } //movl[i]=totlr[i-1]; // chu("movl[%d]:%d\n",i,movl[i]); } lstb=0; totrb[len+1]=totrr[len+1]=0; f_(i,len,1) { if(s[i]=='B') { totrb[i]=totrb[i+1]+1; totrr[i]=totrr[i+1]; movr[i]=movr[lstb]+1LL*totrr[i+1]; lstb=i; } else { totrb[i]=totrb[i+1]; totrr[i]=totrr[i+1]+1; movr[i]=movr[i+1]; } //movr[i]=totrr[i+1]; // chu("movr[%d]:%d\n",i,movr[i]); } ll yes=1e18; int cut=0;//1--cut全部左移 int nowlen=(len>>1); // _f(i,0,nowlen+1) // chu("%lld\n",getans(1,nowlen,i)); // return ; _f(i,1,nowlen)//枚举起点 { int l=i,r=i+nowlen-1; ll nxt=1e18,now=getans(l,r,cut); _f(j,cut,r) { nxt=getans(l,r,j+1); if(now<nxt) { cut=j;break; } else cut=j; now=nxt; } //chu("st:%d--ed:%d cut;%d ans:%lld\n",l,r,cut,getans(l,r,cut)); yes=min(yes,now); } chu("%lld\n",yes); } int main() { t=re(); while(t--) { deal(); } return 0; }