高二上一调

【比赛】这次应该叫高二上一调 - 比赛 - 衡中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;
}
View Code

 

posted on 2022-07-08 11:27  HZOI-曹蓉  阅读(38)  评论(0编辑  收藏  举报