noip模拟7

T1 匹配

真 水题
枚举区间长度,计算区间 \(hash\) 值,kmp跳 \(next\) 都可以。

hash
#include<cstdio>
#define MAX 100001
#define re register
#define ull unsigned long long
namespace OMA
{
   int t,la,lb;
   int l,r,mid;
   char a[MAX<<1],b[MAX],ch;
   const ull base=131;
   ull bin[MAX]={1};
   ull hasha[MAX<<1],hashb[MAX];
   inline int min(int a,int b)
   { return a<b?a:b; }
   signed main()
   {
     scanf("%d",&t);
     for(re int i=1; i<=MAX; i++)
     { bin[i] = bin[i-1]*base; }
     for(t; t; t--)
     {
       bool flag = false;
       scanf("%d%d",&la,&lb);
       scanf("%s",a+1);
       scanf(" %c",&ch);
       for(re int i=1; i<=lb; i++)
       { b[i] = a[i]; }
       b[lb+1] = ch;
       for(re int i=1; i<=la; i++)
       { hasha[i] = hasha[i-1]*base+a[i]; }
       for(re int i=1; i<=lb+1; i++)
       { hashb[i] = hashb[i-1]*base+b[i]; }
       for(re int x=min(la,lb+1); x>=1; x--)
       {
         if(hasha[x]==hashb[lb+1]-hashb[lb+1-x]*bin[x])
         { printf("%d\n",x); flag = true; break ; }
       }
       if(!flag)
       { printf("0\n"); }
     }
     return 0;
   }
}
signed main()
{ return OMA::main(); }
kmp
#include<cstdio>
#define MAX 100001
#define re register
namespace OMA
{
   int t;
   int next[MAX*3];
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline int min(int a,int b)
   { return a<b?a:b; }
   signed main()
   {
     t = read();
     for(t; t; t--)
     {
       char s[MAX*3],ch;
       int la=read(),lb=read();
       scanf("%s",s+1);
       scanf(" %c",&ch);
       for(re int i=1; i<=lb; i++)
       { s[i+la] = s[i]; }
       s[la+lb+1] = ch;
       for(re int i=0; i<=la+lb+1; i++)
       { next[i] = 0; }
       for(re int i=2,j=0; i<=la+lb+1; i++)
       {
         while(j&&s[i]!=s[j+1])
         { j = next[j]; }
         next[i] = j += (s[i]==s[j+1])?1:0;
       }
       int temp=la+lb+1,tmp=min(la,lb+1);
       while(next[temp]>tmp)
       { temp = next[temp]; }
       printf("%d\n",next[temp]);
     }
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T2 回家

逃学
看上去像个割点,但单纯的割点并不对,割点不一定是必经点,但必经点一定是割点,所以要对朴素的割点做一下修改。

我们设\(pre[v]=u\) 表示 \(v\) 是由 \(u\) 转移过来的,在 \(tarjan\) 的过程中我们仅算出 \(low\)\(dfn\),不用去找出所有的割点,因为我们只需要那些与 \(n\) 有关的割点。

在跑完 \(tarjan\) 后直接去循环跳节点 \(n\)\(pre\),在跳的过程中,判断 \(n\)\(pre\) 是否为割点,如果是则为必经点。

当跳到1的时候,记得 \(break\) 。记录完答案后记得 \(sort\) 一遍,因为 \(pre\) 之间的大小关系不确定。

还有一种方法用缩点,但我没码,所以blog

一定要看数据范围QAQ \(m\le2n\)

Code
#include<cstdio>
#include<algorithm>
#define MAX 200001
#define re register
namespace OMA
{
   int t,n,m;
   struct node
   {
     int next;
     int to;
   }edge[MAX<<2];
   int num,cnt,head[MAX];
   int pre[MAX],ans[MAX];
   int dfn[MAX],low[MAX];
   inline int read()
   {
     int s=0,w=1; char ch=getchar();
     while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
     while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
     return s*w;
   }
   inline void clear()
   {
     cnt = 1,num = 0;
     for(re int i=1; i<=MAX; i++)
     { pre[i] = head[i] = dfn[i] = low[i] = ans[i] = 0; }
   }
   inline void add(int u,int v)
   {
     edge[++cnt].next = head[u];
     edge[cnt].to = v;
     head[u] = cnt;
   }
   inline int min(int a,int b)
   { return a<b?a:b; }
   inline void tarjan(int u,int from)
   {
     pre[u] = from;
     dfn[u] = low[u] = ++num;
     for(re int i=head[u]; i; i=edge[i].next)
     {
       int v = edge[i].to;
       if(!dfn[v])
       {
         tarjan(v,u);
         low[u] = min(low[u],low[v]);
       }
       else if(v!=from)
       { low[u] = min(low[u],dfn[v]); }
     }
   }
   signed main()
   {
     t = read();
     for(t; t; t--)
     {
       clear();
       n = read(),m = read();
       for(re int i=1; i<=m; i++)
       {
         int u=read(),v=read();
         add(u,v),add(v,u);
       }
       for(re int i=1; i<=n; i++)
       {
         if(!dfn[i])
         { tarjan(i,0); }
       }
       cnt = 0;
       for(re int i=n; i; i=pre[i])
       {
         if(pre[i]==1)
         { break; }
         if(low[i]>=dfn[pre[i]])
         { ans[++cnt] = pre[i]; }
       }
       std::sort(ans+1,ans+1+cnt);
       printf("%d\n",cnt);
       for(re int i=1; i<=cnt; i++)
       { printf("%d ",ans[i]); }
       printf("\n");
     }
     return 0;
   }
}
signed main()
{ return OMA::main(); }

T3 寿司

没改出来 快了快了
三种做法
单调指针乱扫 最优解,也是正解
大根堆 来自zero4338,思路很妙
以及玄学取中点 挺多人写这个的,我也没码.然而并不会证,但能ac

Code
#include<queue>
#include<cstdio>
#include<cstring>
#define MAX 1000001
#define re register
#define int long long
namespace OMA
{
   int len;
   int t,R,B;
   char ch[MAX];
   int val[MAX],cnt[3],sum,tot,ans;
   struct node
   {
     int delta;
     std::priority_queue<int>q;
     inline void clear()
     {
       while(!q.empty())
       { q.pop(); }
       delta = sum = cnt[0] = cnt[1] = cnt[2] = 0;
     }
     inline int abs(int a)
     { return a>=0?a:-a; }
   }q;
   inline int min(int a,int b)
   { return a<b?a:b; }
   signed main()
   {
     scanf("%lld",&t);
     for(t; t; t--)
     {
       q.clear();
       R = B = 0;
       scanf("%s",ch+1);
       len = strlen(ch+1);
       for(re int i=1; i<=len; i++)
       {
         if(ch[i]=='B')
         { B++; }
         else
         { val[i] = B; R++; }
       }
       for(re int i=len; i>=1; i--)
       {
         if(ch[i]=='B')
         { cnt[0]++; }
         else
         {
           val[i] -= cnt[0];
           if(val[i]<0)
           { q.q.push(val[i]); cnt[1]++; }
           else
           { cnt[2]++; }
           sum += q.abs(val[i]);
         }
       }
       ans = (tot = R*B)-sum;
       for(re int i=len; i>=1; i--)
       {
         if(ch[i]=='R')
         {
           cnt[1]++,cnt[2]--;
           q.q.push(-B-q.delta);
         }
         else
         {
           q.delta += 2;
           sum += 2*(cnt[2]-cnt[1]);
           while(!q.q.empty())
           {
             int now = q.q.top();
             if(now+q.delta>=0)
             {
               cnt[1]--,cnt[2]++;
               q.q.pop();
               if(now+q.delta==1)
               { sum += 2; }
             }
             else
             { break; }
           }
           ans = min(ans,tot-sum);
         }
       }
       printf("%lld\n",ans/2);
     }
     return 0;
   }
}
signed main()
{ return OMA::main(); }
posted @ 2021-06-11 18:29  -OMA-  阅读(116)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end