Noip模擬7
阿新 • • 發佈:2021-06-11
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();}