Noip模拟7
T1 匹配
题目描述
考场上忘记如何打KMP了,于是就用暴力hash水过去了。
然而数组开小了,痛失5pts...
CODE
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
namespace EMT
{
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x * f;
}
#define F(i, a, b) for (register int i = a; i <= b; i++)
#define f(x) for (register int i = head[x], j; i; i = e[i].next)
#define pf printf
inline void pi(int x)
{
pf("%d ", x);
}
inline void pn() { printf("\n"); }
inline void ps(int a[], int size)
{
F(i, 1, size)
pi(a[i]);
pn();
}const int N=1e6+100;
#define ull unsigned long long
int T,lena,lenb;char sa[N],t;
ull hasha[N],hashb[N],p[N];
inline short main(){
T=read();p[0]=1;
F(i,1,N-100)p[i]=p[i-1]*131;
while(T--){
lena=read();lenb=read();
scanf("%s",sa+1);t=getchar();
while(t>'z'||t<'a')t=getchar();
F(i,1,lena)hasha[i]=hasha[i-1]*131+sa[i];
F(i,1,lenb)hashb[i]=hasha[i];lenb++;
hashb[lenb]=hashb[lenb-1]*131+t;
int ans=0;
for(register int i=min(lena,lenb);i>=1;i--)
if(hasha[i]==hashb[lenb]-hashb[lenb-i]*p[i]){ans=i;break;}
pi(ans);pn();
}return 0;
}
}
int main(){return EMT::main();}
T2 回家
题目描述
考场上忘记tj如何求割点了。。。还是得复习一下。
本题就是先求出每个点的DFN和LOW,
从1节点开始遍历到n并记录路径,
只有路上的割点才能算作必经点,记录输出即可。
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
namespace EMT
{
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
x = x * 10 + ch - '0', ch = getchar();
return x * f;
}
#define F(i, a, b) for (register int i = a; i <= b; i++)
#define f(x) for (register int i = head[x], j; i; i = e[i].next)
#define pf printf
inline void pi(int x)
{
pf("%d ", x);
}
inline void pn() { printf("\n"); }
inline void ps(int a[], int size)
{
F(i, 1, size)
pi(a[i]);
pn();
}
const int N=8e5+100;
int rec[N],cou,T,n,m,co,tim,head[N],root,dfn[N],low[N],fa[N];bool bg[N],v[N],in[N];struct node{int next,to;}e[N<<1];
void add(int next,int to){e[++co].next=head[next],e[co].to=to,head[next]=co;}
inline void tj(int x){
low[x]=dfn[x]=++tim;int fl=0;
f(x){
j=e[i].to;
if(!dfn[j]){
tj(j);fa[j]=x;
low[x]=min(low[x],low[j]);
}else low[x]=min(low[x],dfn[j]);
}
}
int main(){
// freopen("home1.in","r",stdin);
// freopen("my.out","w",stdout);
T=read();
while(T--){
n=read(),m=read();
memset(head,0,sizeof(head));memset(dfn,0,sizeof(dfn));
memset(bg,0,sizeof(bg));memset(in,0,sizeof(in));
memset(low,0,sizeof(low));memset(v,0,sizeof(v));
memset(fa,0,sizeof(fa));
co=cou=tim=0;
F(i,1,m){
int x=read(),y=read();
if(x==y)continue;
add(x,y);add(y,x);
}
tj(1);
int x=n;
while(x!=1){
int f=fa[x];
if(f!=1&&f!=n&&low[x]>=dfn[f])rec[++cou]=f;
x=f;
}
sort(rec+1,rec+cou+1);
pi(cou);pn();
F(i,1,cou)pi(rec[i]);
pn();
}
return 0;
}
}
int main(){return EMT::main();}
T3 寿司
题目描述
在与掰的误导与ICEY的正确引导下A掉了。
引用一下:
发现对于一个序列,肯定是左边一部分往左靠,右边一部分往右靠,于是可以每次二分出这个边界点。
时间复杂度\((nlogn)\),可以得到80到100分。
下面是我的思路:
设\(li\),\(ri\)为i点左边和右边分别有几个B
发现答案是\(\sum_{i=1}^{n}min(li,ri)\)
先暴力统计出原序列的答案,再枚举其他序列。
对于一个新序列,不妨认为是上一个序列的第一个字母移到最后一位产生的,
那么如果移动的字母是\(R\),\(min(li,ri)\)不变仍为0,对其他\(R\)的\(li\),\(ri\)没有影响,直接跳过
否则,序列中的\(R\)每个\(li-1\),\(ri+1\).
想一下,如果一个\(R\)原来的\(li<=ri\),那么\(li\)变成\(li-1\),更小了,ans相应减一,\(li>=ri+2\)的话同理会加一,\(li=ri+1\)的话答案不变,
用前缀和可以\(O(1)\)求出\(li\),\(ri\).二分出上述所说的两种产生贡献的\(R\)个数即可。
Code
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
namespace EMT{
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
#define pf printf
typedef long long ll;
void pi(ll x){pf("%lld ",x);}void pn(){pf("\n");}void ps(int a[],int size){F(i,1,size)pi(a[i]);pn();}
inline int read(){int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x;}
const int N=1e6+100;ll end,tot;
int T;ll cnt,totb,n,a[N<<1],lr[N<<1];char s[N];
inline ll abs(ll a){return a<0?-a:a;}
inline ll min(ll a,ll b){return a<b?a:b;}
inline short main(){
T=read();
while(T--){
scanf("%s",s+1);
int Len=strlen(s+1);
totb=cnt=end=n=tot=0;
memset(a,0,sizeof(a));memset(lr,0,sizeof(lr));
F(i,1,Len){
n++;
if(s[i]=='B')a[n]=1,lr[n]=cnt,totb++;
else lr[n]=++cnt;
}
F(i,n+1,n*2)a[i]=a[i-n];
F(i,1,2*n)a[i]=a[i-1]+a[i];
F(i,n+1,n*2)lr[i]=lr[i-1]+(a[i]==a[i-1]);
F(i,1,n)if(a[i]==a[i-1])tot+=min(a[i],(totb-a[i]));end=tot;
F(i,1,n-1){
if(a[i]==a[i-1])continue;
int l=i,r=n+i-1,ans1=i-1;
while(l<=r){
int mid=(l+r)>>1;
if(((a[mid]-a[i-1])<<1)<=totb)l=mid+1,ans1=mid;
else r=mid-1;
}
l=ans1+1,r=n+i-1;int ans2=i+n;
while(l<=r){
int mid=(l+r)>>1;
if(((a[mid]-a[i-1])<<1)>=totb+2)ans2=mid,r=mid-1;
else l=mid+1;
}
tot-=(lr[ans1]-lr[i-1])-(lr[i+n-1]-lr[ans2-1]);
end=min(tot,end);
}
pi(end);pn();
}return 0;
}
}
signed main(){return EMT::main();}
Everything that kills me makes me feel alive.