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(); }