1. 程式人生 > 其它 >noip模擬64(待補)

noip模擬64(待補)

「三元組·簡單的字串·環路·過河」

A. 三元組

簽到題,樹狀陣列亂寫就行了.

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long int
	#define ull unsigned ll
	#define lf double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		ll res=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
		return cit?res:-res;
	}
} using namespace BSS;

const ll N=1e5+21;

ll Ts,n,mod,ans,cnt;

ll vis[N],bin[N];
struct Bit_Array{
	ll res; ll c[N<<1];
	inline void update(ll x,ll w){
		if(x<=0){ c[0]+=w; return ; }
		for(;x<mod;x+=lbt(x)) c[x]+=w;
	}
	inline void del(ll x){
		if(x<=0){ c[0]=0; return ;}
		for(;x<mod;x+=lbt(x)) c[x]=0;
	}
	inline ll query(ll x){
		res=0+c[0]*(x>=0);
		for(;x>0;x&=(x-1)) res+=c[x]; return res;
	}
	inline ll ask(ll l,ll r){
		return query(r)-query(l-1); 
	}
}bit;
signed main(){
	File(exclaim);
	Ts=read(); ll l,r,tmp=0;
	for(int T=1;T<=Ts;T++){
		n=read(),mod=read(),ans=0,cnt=0;
		for(ll i=n;i>=1;i--){
			tmp=i*i*i%mod,bit.update(tmp,1);	
			if(!vis[tmp]) vis[tmp]=1,bin[++cnt]=tmp;
			if(i%mod==0) ans+=bit.ask(0,mod-1)*(i/mod);
			else 
			{
				l=(i*i+1)%mod,r=(i*i+i)%mod;	
				ans+=bit.ask(0,mod-1)*(i/mod);
				if(l<=r) ans+=bit.ask(l,r);
				else ans+=bit.ask(l,mod-1)+bit.ask(0,r);
			}
		}
		for(int i=1;i<=cnt;i++) bit.del(bin[i]),vis[bin[i]]=0;
		printf("Case %d: %lld\n",T,ans);
	}
	exit(0);
}

B. 簡單的字串

不會迴文樹,也不會 \(manacher\).

考場上就想到了這個題目的所有性質.

但是差一個 \(Border\) 理論 (膜拜這位 \(dalao\),講得很清晰.)

考後看到題解中說到只會跳兩三次,於是覺得暴跳 \(kmp\) 就行了.

雖然這樣也能 \(A\),但實際上覆雜度是假的,可以被卡成 \(O(n^3)\).

本以為這樣就結束了,但是多虧 \(Yubai\) 來問我這題做法(因為貌似只有我一個人是用 \(kmp\) \(A\) 掉的).

實際上我們完全可以去掉一維.

如果會了上面的理論,那麼這就是個板子題了,現在正式進入題解.

我們發現答案其實就是由 \(A+B+B+A\)

構成的一個字串(\(A,B\) 是字串,\(B\)可以為空).

考慮得到 \(A\)

然後我們在每個子區間 \([l,r]\) 分別處理出來 \(ta\)\(border\).

我們發現這個 \(border\) 長度可能大於 \(\dfrac{r-l+1}{2}\),考慮把 \(ta\) 縮小到一般長度以內.

只要學會上面的理論,這個東西還是很好說的.

設子串 \([l,r]\)\(S\).

由於大於 \(\dfrac{len_s}{2}\)\(Border\) 的長度為一個等差序列。

所以可以求出 \(S\)\(Max\ Border\),然後求出 \(Max\ Border\)

\(Max\ Border\) ,設兩個 \(Max\ Border\) 分別為 \(M_1,M_2\).

公差就是 \(M_1\ - \ M_2\).

於是 \(A\) 便可以跳公差求出了.

考慮得到 \(B\)

我們可以列舉中點,然後 \(Hash\) 得到中間 \(B\) 的部分.

這裡建議結合 \(PPT\) 中給出的題解一起理解.

到此我們得到了 \(A\)\(B\)..

我們得到了最長的 \(A\) 和最長的 \(B\) 之後,餘下的我們分別進行判斷.

這裡都要判斷,並不取決於 \(A\)\(B\) 的相對大小而選擇捨棄哪一個.

這裡有 \(Yubai\) 的手模樣例:1 1 1 1 1 1 2 1 1 2 1 1 1 1 1 1 . 樣例說明並不能捨棄某種判斷.

至此本題結束,並膜掰.

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll int
	#define ull unsigned ll
	#define lf double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
	inline ll read() {
		ll res=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
		return cit?res:-res;
	}
} using namespace BSS;

const ll N=6e3+21;
const ull P=131;	

ll m,n,ans;
ll nxt[N][N],bd[N][N];
ull pre[N],po[N],sp[N];
inline void PUT(ll l,ll r){ for(int i=l;i<=r;i++) cout<<sp[i]<<' '; puts(""); }
inline ull getsh(ll l,ll r){ 
	return 1u*pre[r]-1u*pre[l-1]*po[r-l+1]; 
}
inline void getnxt(){
	for(int st=1;st<=n;st++){
		for(int i=st-1;i<=n;i++) nxt[st][i]=st-1;
		for(int i=st+1,j=st-1;i<=n;i++){
			while(j>st-1 and sp[i]!=sp[j+1]) j=nxt[st][j];
			if(sp[i]==sp[j+1]) nxt[st][i]=++j;
			else nxt[st][i]=st-1;
		}
	}
}
inline void getbord(){
	for(int mid=1;mid<n;mid++){ // 列舉中點
		ll lmt=min(mid,n-mid);
		for(int l=1;l<=lmt;l++){ 
			bd[mid][l]=bd[mid][l-1];
			if(getsh(mid-l+1,mid)==getsh(mid+1,mid+l)) bd[mid][l]=l;
		}
	}
}
inline bool check(ll l,ll r){
	ll mid=(l+r)>>1,nownxt=nxt[l][r];
	if(nownxt>mid){
		ll nxtnxt=nxt[l][nownxt],delta=nownxt-nxtnxt;
		nownxt=nownxt-delta*((nownxt-mid)/mid);
		if(nownxt>mid) nownxt=nxt[l][nownxt];
	}
	if(nownxt==mid) return 1;
	if(getsh(nownxt+1,mid)==getsh(mid+1,2*mid-nownxt)) return 1;
	ll len=r-mid,nowbd=bd[mid][len],br=mid+nowbd,bl=mid-nowbd+1;
	if(l==bl and r==br) return 1;
	if(getsh(l,bl-1)==getsh(br+1,r)) return 1;
	return 0;
}
signed main(){
	File(s);
	n=read(),po[0]=1;
	for(int i=1;i<=n;i++){
		sp[i]=read();
		pre[i]=pre[i-1]*P+sp[i],po[i]=po[i-1]*P;
	}
	getnxt(),getbord();
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j+=2){
 			if(nxt[i][j]<i) continue;
			ans+=check(i,j);
		}
	}
	printf("%d\n",ans),exit(0);
}

C. 環路

D. 過河