noip模拟25[random·string·queen]

noip模拟25 solutions

还是wzz的,依旧无法做出,勉勉强强的第一题拿了70pts,感觉自己菜到家了

啥也不会,啥也推不出来。。。。

T1 random

这个就是一个打表找规律的题,我首先打表打出来,一个序列中如果有n个逆序对,

那么他的总贡献就是\(\frac{4}{3}n\),题解上是直接统计的一个长为n的序列的总贡献

然后就继续打表,最后就得到了最后的\(\huge\sum\limits_{i=1}^{n}\frac{\frac{i(i-1)}{3}}{n}\)

为啥没拿满分呢,因为不会公式,然后考完之后一化简,直接输出\(\frac{n^2-1}{9}\)就好了

注意n,m超级大,先给他俩取个模

AC_code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=998244353;
ll T;
ll ksm(ll x,ll y){
	ll ret=1;
	while(y){
		if(y&1)ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
ll N;
signed main(){
	scanf("%lld",&T);
	while(T--){
		scanf("%lld",&N);
		printf("%lld\n",((N%mod)*(N%mod)%mod-1+mod)%mod*ksm(9,mod-2)%mod);
	}
}

T2 string

这个就是暴力\(hash\),考场上忘记\(hash\)咋写了,暴力取了个模,又WA又T的

所以我向\(Varuxn\)学习了\(unsigned long long\)不取模的做法,搞到了40pts

自己学习了题解部分分做法,搞到了\(90pts\),虽然别人都只有\(70pts\)

虽然隔壁的Varuxn卡到了80,还是菜。。。。。。

咱也不知道为啥咱的暴力总是特别快,哈哈哈哈,咱就是牛逼,!!!!!!

90pts
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ull unsigned long long
const int N=1e5+5;
const ull bas=131;
char s[N],c[N*3];
int len[N],n,sum;
ull hs[N],ba[N],ans;
vector<ull> ha[N];
ull f[N],g[N];
signed main(){
	scanf("%s",s+1);
	len[0]=strlen(s+1);
	for(re i=1;i<=len[0];i++)
		hs[i]=hs[i-1]*bas+s[i]-'a';
	scanf("%d",&n);
	ba[0]=1;for(re i=1;i<N;i++)ba[i]=ba[i-1]*bas;
	for(re i=1;i<=n;i++){
		scanf("%s",c+sum+1);
		len[i]=strlen(c+sum+1);
		//cout<<len[i]<<" "<<sum<<endl;
		ha[i].resize(len[i]+3);
		for(re j=sum+1;j<=len[i]+sum;j++)
			ha[i][j-sum]=ha[i][j-sum-1]*bas+c[j]-'a';
		sum+=len[i];
	}
	for(re x=1;x<=len[0];x++){
		for(re i=1;i<=n;i++){
			for(re l=1;l<=len[i];l++){
				ull tmp0=hs[x+l-1]-hs[x-1]*ba[l];
				ull tmp1=ha[i][l];
				if(tmp0==tmp1)g[x]++;
				else break;
			}
			for(re r=1;r<=len[i];r++){
				ull tmp0=hs[x]-hs[x-r]*ba[r];
				ull tmp1=ha[i][len[i]]-ha[i][len[i]-r]*ba[r];
				if(tmp0==tmp1)f[x]++;
				else break;
			}
		}
	}
	for(re i=1;i<len[0];i++)ans+=f[i]*g[i+1];
	printf("%llu",ans);
}

正解吧,把每个小串前缀后缀放到\(Trie\)上,开两个树,一个存前缀,一个存后缀

还有二分,我们枚举大串的每一个断点,向左右两侧寻找可以匹配的串的个数

这个时候就用到了\(trie\),插入的时候,让走过的每一个节点的权值++

\(dfs\),将每一个节点的权值,下放到儿子节点,顺便吧这个链的\(hash\)值求出来

\(hash\)值和此时的权值放到\(map\)里,注意用\(unordered_map\),这个还快一些

二分断点左右两侧能够匹配的长度,如果手写map的话可以\(O(nlogn)\)

我这个常数稍微大一些,注意用find函数,别直接用[]慢好多

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ull unsigned long long
const int N=1e5+5;
const int bas=131;
char s[N],cc[N];
vector<char> c[N];
ull hs[2][N],ba[N];
ull f[N],g[N],ans;
int len[N],n;
struct TRIE{
	int siz[N*3],son[N*3][30];
	int seg;
	unordered_map<ull,int> mp;
	TRIE(){seg=1;}
	void ins(int x,int i,int dep){
		if(dep==c[i].size())return ;
		int w=c[i][dep]-'a'+1;
		if(!son[x][w])son[x][w]=++seg;
		siz[son[x][w]]++;
		ins(son[x][w],i,dep+1);
	}
	void dfs(int x,ull ha){
		mp[ha]=siz[x];
		//cout<<ha<<" "<<siz[x]<<endl;
		for(re i=1;i<=26;i++){
			if(!son[x][i])continue;
			//cout<<x<<" "<<i<<" "<<ha*bas+i<<endl;
			siz[son[x][i]]+=siz[x];
			dfs(son[x][i],ha*bas+i);
		}
	}
}fro,beh;
signed main(){
	scanf("%s",s);
	len[0]=strlen(s);
	scanf("%d",&n);
	for(re i=1;i<=n;i++){
		scanf("%s",cc+1);
		len[i]=strlen(cc+1);
		for(re j=1;j<=len[i];j++)
			c[i].push_back(cc[j]);
	}
	for(re i=1;i<=n;i++)fro.ins(1,i,0);
	for(re i=1;i<=n;i++)reverse(c[i].begin(),c[i].end());
	for(re i=1;i<=n;i++)beh.ins(1,i,0);
	fro.dfs(1,0);beh.dfs(1,0);
	ba[0]=1;
	for(re i=1;i<=len[0];i++){
		hs[0][i]=hs[0][i-1]*bas+s[i-1]-'a'+1;
		ba[i]=ba[i-1]*bas;
	}
	for(re i=len[0];i>=1;i--){
		hs[1][i]=hs[1][i+1]*bas+s[i-1]-'a'+1;
	}
	for(re i=1;i<=len[0];i++){
		/*for(re l=1;l<=len[0]-i+1;l++){
			ull tmp=hs[0][i+l-1]-hs[0][i-1]*ba[l];
			if(fro.mp[tmp])g[i]+=fro.mp[tmp];
			else break;
		}
		for(re r=1;r<=i;r++){
			ull tmp=hs[1][i-r+1]-hs[1][i+1]*ba[r];
			if(beh.mp[tmp])f[i]+=beh.mp[tmp];
			else break;
		}*/
		ull res;
		int l=1,r=len[0]-i+1,mid;
		res=hs[0][i]-hs[0][i-1]*bas;
		if(fro.mp.find(res)==fro.mp.end())g[i]=0;
		else{
			while(l<r){
				mid=l+r+1>>1;
				ull tmp=hs[0][i+mid-1]-hs[0][i-1]*ba[mid];
				if(fro.mp.find(tmp)!=fro.mp.end())l=mid;
				else r=mid-1;
			}
			res=hs[0][i+l-1]-hs[0][i-1]*ba[l];
			g[i]=fro.mp[res];
		}
		//cout<<i<<" "<<l<<" ";
		l=1;r=i;
		res=hs[1][i]-hs[1][i+1]*bas;
		if(beh.mp.find(res)==beh.mp.end())f[i]=0;
		else{
			while(l<r){
				mid=l+r+1>>1;
				ull tmp=hs[1][i-mid+1]-hs[1][i+1]*ba[mid];
				if(beh.mp.find(tmp)!=beh.mp.end())l=mid;
				else r=mid-1;
			}
			res=hs[1][i-l+1]-hs[1][i+1]*ba[l];
			f[i]=beh.mp[res];
			//cout<<res<<" "<<l<<" "<<endl;
			//cout<<res<<" "<<l<<endl;
		}
	}
	for(re i=1;i<len[0];i++)ans+=f[i]*g[i+1];//cout<<f[i]<<" "<<g[i]<<endl;
	printf("%llu",ans);
}

T3 queen

就这,就这,就这啊!!!!

我没压行,而且吧,还把一行拆成两行了,你们不需要缩放页面!!!!

就推个式子,简简单单轻轻松松,题解说的挺明白,你要是想拍啊

就把代码粘走???

AC_code(缩放80%)
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int mod=3e5+7;
ll T,n,m,k,ans;
ll jc[mod+10],inv[mod+10];
ll ksm(ll x,ll y){
	ll ret=1;
	x%=mod;
	while(y){
		if(y&1)ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}
ll W(ll x,ll y){
	if(x<y)return 0;
	//cout<<inv[y]%mod*inv[(x-y+mod)%mod]%mod<<" "<<ksm(jc[y]*jc[(x-y+mod)%mod]%mod,mod-2)<<endl;
	return jc[x]*inv[y]%mod*inv[(x-y+mod)%mod]%mod;
	//return jc[x]*ksm(jc[y]*jc[(x-y+mod)%mod]%mod,mod-2)%mod;
}
ll C(ll x,ll y){
	if(x<y)return 0;
	if(!x||!y)return 1;
	return C(x/mod,y/mod)*W(x%mod,y%mod)%mod;
}
signed main(){
	jc[0]=1;inv[0]=1;
	for(re i=1;i<=mod;i++)jc[i]=jc[i-1]*i%mod;
	inv[mod-1]=ksm(jc[mod-1],mod-2);
	for(re i=mod-2;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
	scanf("%lld",&T);
	while(T--){
		ans=0;
		scanf("%lld%lld%lld",&n,&m,&k);
		ans=(ans+(m%mod)*C(n,k)%mod)%mod;
		ans=(ans+(n%mod)*C(m,k)%mod)%mod;
		ll nn=max(n,m),mm=min(n,m);
		ans=(ans+2*(C(mm+1,k+1)*2+max(nn-mm-1,0ll)%mod*C(mm,k))%mod)%mod;
		if(n==m)ans=(ans+2*mod-2*C(m,k))%mod;
		if(k==1)ans=(n%mod)*(m%mod)%mod;
		if(k==3){
			ll mi=min(n-1,(m-1)/2);
			//cout<<ans<<endl;
			ans=(ans+2*((n%mod)*(m%mod)%mod*(mi%mod)%mod+mod-(m+2*n)%mod*((mi%mod)*((mi+1)%mod))%mod*ksm(2,mod-2)%mod
				+ksm(3,mod-2)*(mi%mod)%mod*((mi+1)%mod)%mod*((mi*2+1)%mod)%mod)%mod)%mod;
			swap(m,n);
			mi=min(n-1,(m-1)/2);
			//cout<<ans<<endl;
			ans=(ans+2*((n%mod)*(m%mod)%mod*(mi%mod)%mod+mod-(m+2*n)%mod*((mi%mod)*((mi+1)%mod))%mod*ksm(2,mod-2)%mod
				+ksm(3,mod-2)*(mi%mod)%mod*((mi+1)%mod)%mod*((mi*2+1)%mod)%mod)%mod)%mod;
			swap(m,n);
			//cout<<ans<<endl;
			mi=min(n-1,m-1);
			ans=(ans+4*((n%mod)*(m%mod)%mod*(mi%mod)%mod+mod-((m+n)%mod)*(mi%mod)%mod*((mi+1)%mod)%mod*ksm(2,mod-2)%mod
				+ksm(6,mod-2)*(mi%mod)%mod*((mi+1)%mod)%mod*((mi*2+1)%mod)%mod)%mod)%mod;
		}
		if(k==4){
			ll mi=min(n-1,(m-1)/2);
			//cout<<ans<<endl;
			ans=(ans+2*((n%mod)*(m%mod)%mod*(mi%mod)%mod+mod-(m+2*n)%mod*((mi%mod)*((mi+1)%mod))%mod*ksm(2,mod-2)%mod
				+ksm(3,mod-2)*(mi%mod)%mod*((mi+1)%mod)%mod*((mi*2+1)%mod)%mod)%mod)%mod;
			swap(m,n);
			mi=min(n-1,(m-1)/2);
			//cout<<ans<<endl;
			ans=(ans+2*((n%mod)*(m%mod)%mod*(mi%mod)%mod+mod-(m+2*n)%mod*((mi%mod)*((mi+1)%mod))%mod*ksm(2,mod-2)%mod
				+ksm(3,mod-2)*(mi%mod)%mod*((mi+1)%mod)%mod*((mi*2+1)%mod)%mod)%mod)%mod;
			mi=min((m-1)/2,(n-1)/2);
			ans=(ans+5*((n%mod)*(m%mod)%mod*(mi%mod)%mod+mod-(2*(m+n)%mod)*(mi%mod)%mod*((mi+1)%mod)%mod*ksm(2,mod-2)%mod
				+4*ksm(6,mod-2)%mod*(mi%mod)%mod*((mi+1)%mod)%mod*((mi*2+1)%mod)%mod)%mod)%mod;
			mi=min(n-1,m-1);
			ans=(ans+((n%mod)*(m%mod)%mod*(mi%mod)%mod+mod-((m+n)%mod)*(mi%mod)%mod*((mi+1)%mod)%mod*ksm(2,mod-2)%mod
				+ksm(6,mod-2)*(mi%mod)%mod*((mi+1)%mod)%mod*((mi*2+1)%mod)%mod)%mod)%mod;
		}
		if(k==5){
			ll mi=min((m-1)/2,(n-1)/2);
			ans=(ans+2*((n%mod)*(m%mod)%mod*(mi%mod)%mod+mod-(2*(m+n)%mod)*(mi%mod)%mod*((mi+1)%mod)%mod*ksm(2,mod-2)%mod
				+4*ksm(6,mod-2)%mod*(mi%mod)%mod*((mi+1)%mod)%mod*((mi*2+1)%mod)%mod)%mod)%mod;
		}
		printf("%lld\n",ans);
	}
}
posted @ 2021-07-28 07:00  fengwu2005  阅读(65)  评论(0编辑  收藏  举报