Loading

noip模拟45

A. 打表

不知道该怎么想到这一类的题.
看起来像是推理性质,然后得到一个复杂度简洁的式子吧..

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll long long int 
	#define ull unsigend ll
	#define re register 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 File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memcpy(x,y,sizeof x)
	inline ll read() {
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll mod=1e9+7;
const ll N=1<<19;
ll n,m,ans;
ll w[N];
inline ll ksm(ll a,ll b,ll c){
	a%=c; ll temp=1;
	while(b){
		if(b&1) temp=(temp*a)%c;
		a=(a*a)%c,b>>=1;
	}
	return temp%c;
}
signed main(){
	n=read(),m=read();
	for(re i=0;i<(1<<n);++i) w[i]=read();
	for(re i=0;i<(1<<n);++i)
		(ans+=abs(w[i]-w[m]))%=mod;
	ans=(ans*ksm(1ll<<n,mod-2,mod))%mod;
	printf("%lld",ans);
	return 0;
}

B. 蛇

虽然是字符构成的题目,但如果仅仅局限于\(Hash\)\(Kmp\)、自动机等算法就太狭隘了.
正解是\(dp\),我们发现向四周转移比较困难,考虑如何简化问题.
经过一种不知名的观察我们可以发现,\(ta\) 的行走路线一定是以下形式.(图来源于网络,非原创)
image
于是我们第一个蓝线左边可以预处理,两个蓝线之间可以只单方向的\(dp\),第二个蓝线右边可以在\(dp\)之后处理.
发现\(ta\)可以翻转过来再做一遍\(dp\),否则会算少.
特别判断一下 \(len_s==1\)\(len_s==2\) 的情况即可.

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

const ll mod=1e9+7,N=2e3+11;
const ull P=131;

char s[N];
ll n,m,ans;
ull w[N],pw[N],po[N];
ull c[3][N],pc[3][N],sc[3][N];
ll dp[3][N][N][2];
inline void Pre(){
	scanf("%s",s+1); n=strlen(s+1); for(re i=1;i<=n;++i) c[1][i]=s[i]-'a'+1;
	scanf("%s",s+1); for(re i=1;i<=n;++i) c[2][i]=s[i]-'a'+1;
	scanf("%s",s+1); m=strlen(s+1); for(re i=1;i<=m;++i) w[i]=s[i]-'a'+1;
	for(re i=1;i<=2;i++){
		for(re j=1;j<=n;j++) pc[i][j]=pc[i][j-1]*P+c[i][j];
		for(re j=n;j>=1;j--) sc[i][j]=sc[i][j+1]*P+c[i][j];
	}
	ll tmp=max(n,m); po[0]=1;
	for(re i=1;i<=tmp;i++) po[i]=po[i-1]*P;
	for(re i=1;i<=m;i++) pw[i]=pw[i-1]*P+w[i];
}
inline ull getw(ll l,ll r){ return pw[r]-pw[l-1]*po[r-l+1]; } 
inline ull getpc(ll i,ll l,ll r){ return pc[i][r]-pc[i][l-1]*po[r-l+1]; }
inline ull getsc(ll i,ll l,ll r){ return sc[i][l]-sc[i][r+1]*po[r-l+1]; }
inline void Match(){
	for(re i=1;i<=2;i++){
		for(re j=1;j<=n;j++) pc[i][j]=pc[i][j-1]*P+c[i][j];
		for(re j=n;j>=1;j--) sc[i][j]=sc[i][j+1]*P+c[i][j];
	}
	for(re i=1;i<=2;i++){
		for(re j=1;j<=n;j++){
			dp[i][j][1][0]=(w[1]==c[i][j]); // 上下没有被占为 0
			for(re k=2;k<=j;k++){
				dp[i][j][k<<1][1]=(getsc(3-i,j-k+1,j)==getw(1,k) and getpc(i,j-k+1,j)==getw(k+1,k<<1));
			}
		}
	}
	for(re k=1;k<=m;k++){
		for(re i=1;i<=2;i++)
			for(re j=1;j<=n;j++){				
				if(w[k]!=c[i][j]) continue;
				(dp[i][j][k][0]+=(dp[i][j-1][k-1][1]+dp[i][j-1][k-1][0])%mod)%=mod,
				(dp[i][j][k][1]+=dp[3-i][j][k-1][0])%=mod;
			}
	}
	ll len;
	for(re i=1;i<=2;i++){
		for(re j=1;j<=n;j++)
			for(re k=0;k<=m;k++){
				len=(m-k)>>1;
				if(len==1 or (m&1)!=(k&1)) continue ;
				if(k==m) { ans=(ans+dp[i][j][k][1]+dp[i][j][k][0])%mod; continue; }
				if(getpc(i,j+1,j+len)==getw(k+1,k+len) and getsc(3-i,j+1,j+len)==getw(m-len+1,m) and j+len<=n)
					ans=(ans+dp[i][j][k][1]+dp[i][j][k][0])%mod;
			}
	}
}
signed main(){
	Pre(); Match(); 
	if(m==1) printf("%lld\n",ans%mod),exit(0);
	reverse(c[1]+1,c[1]+1+n),reverse(c[2]+1,c[2]+1+n);
	Fill(dp,0);
	Match();
	if(m==2){
		for(re i=1;i<=2;i++){
			for(re j=1;j<=n;j++)
				ans=(ans-(c[i][j]==w[1] and c[3-i][j]==w[2])+mod)%mod;
		}
	}
	printf("%lld\n",ans%mod);
	exit(0);
}

C. 购物

签到题.
这里用了二分,随便判判就行了..

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

const ll N=2e5+51;
ll m,n,alls,ans;
ll w[N];
inline ll Get(ll x){
	ll l=1,r=n,res=r,mid;
	while(l<=r){
		mid=(l+r)>>1;
		if(w[mid]>=x) r=mid-1,res=mid;
		else l=mid+1;
	}
	return res;
}
signed main(){
	n=read();
	for(re i=1;i<=n;++i) alls+=w[i]=read();
	sort(w+1,w+1+n); ll temp=n,pre=0,now,mid,flag;
	for(re i=1;i<=temp;++i)
		pre=pre+w[i],w[++n]=pre;
	sort(w+1,w+1+n); n=unique(w+1,w+1+n)-w-1;
	now=w[n],flag=0;
	while(now){
		mid=(now+1)>>1,ans+=now-mid+1-flag,temp=Get(mid);
		if(now==w[temp]){
			now=w[temp-1],flag=0;
		}
		else{
			now=w[temp],flag=now-mid+1;
		}
	}
	printf("%lld",ans);
	return 0;
}

D. ants

回滚莫队,先鸽了.

posted @ 2021-09-10 15:47  AaMuXiiiiii  阅读(41)  评论(0)    收藏  举报