[CSP-S模拟测试]:(全保密)

Day1


T1

题解

显然是一个撞鸭$DP$,考虑如何定义。

定义$dp[i][j][k]$表示处理到第$i$行,第$i$行的按钮状态为$j$,第$i$行的覆盖状态为$k$的最小代价。

为了方便计算,因为如果一个覆盖状态是当前覆盖状态的子集,也就是说我们可以用当前覆盖状态的代价制造出那个覆盖状态(可以重复覆盖),所以每次将其子集与其取$\min$即可。

时间复杂度:$\Theta(n\times 2^m\times 3^m)$。

代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,m;
char ch[20];
int Map[20][20],state[20],v[20][1100],dp[20][1100][1100],f[1100];
int ans=0x3f3f3f3f;
int main()
{
	memset(dp,0x3f,sizeof(dp));dp[0][0][0]=0;
	scanf("%d%d",&n,&m);
	state[0]=(1<<m)-1;
	for(int i=1;i<=n;i++)
	{
		scanf("%s",ch+1);
		for(int j=1;j<=m;j++)
			if(ch[j]-'0')
				state[i]|=1<<(j-1);
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&Map[i][j]);
	for(int i=1;i<=m;i++)Map[n+1][i]=0x3f3f3f3f;
	for(int i=1;i<=n+1;i++)
		for(int j=0;j<(1<<m);j++)
			for(int k=1;k<=m;k++)
				if(j&(1<<(k-1)))v[i][j]+=Map[i][k];
	for(int i=0;i<(1<<m);i++)
	{
		f[i]=i;
		for(int j=1;j<=m;j++)
			if(i&(1<<(j-1)))
				f[i]|=((1<<(j-2))|(1<<j));
	}
	for(int i=1;i<=n+1;i++)
	{
		for(int j=0;j<(1<<m);j++)
			for(int k=0;k<(1<<m);k++)
				dp[i][j][k|state[i]]=min(dp[i][j][k|state[i]],dp[i-1][k][(~((j|f[k]|state[i-1])&((1<<m)-1)))&((1<<m)-1)]+v[i][j]);
		for(int j=0;j<(1<<m);j++)
			for(int k=(1<<m)-1;k>=0;k--)
				for(int l=k;l;l-=l&-l)
					dp[i][j][k^(l&-l)]=min(dp[i][j][k^(l&-l)],dp[i][j][k]);
	}
	for(int i=0;i<(1<<m);i++)ans=min(ans,dp[n+1][0][i]);
	printf("%d",ans);
	return 0;
}

T2

题解

单独考虑第一问,答案其实就是将$val$排序后$\prod \limits_{i=1}^n\min(i,key_i)$,注意$val$可能相同,不妨设前面$sum$个都与其相同,那么答案就变成了

$$\prod\limits_{i=1}^n\min(i,key_i+sum)$$

再来考虑第二问的构造,问题可以转化为区间最值,线段书维护即可。

时间复杂度:$\Theta(n\log n)$。

代码时刻

#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
const int mod=1000000007;
struct rec{int key,val;}e[500001];
map<int,int>mp;
int n;
int cnt;
long long ans=1;
deque<int>q[500001];
int mn[2000001],id[2000001],lz[2000001];
pair<int,int> tr[2000001];
bool cmp1(rec a,rec b){return a.val==b.val?a.key<b.key:a.val>b.val;}
bool cmp2(rec a,rec b){return a.val==b.val?a.key<b.key:a.val<b.val;}
void pushup(int x)
{
	if(mn[L(x)]<=mn[R(x)]){mn[x]=mn[L(x)];id[x]=id[L(x)];}
	else{mn[x]=mn[R(x)];id[x]=id[R(x)];}
	tr[x]=min(tr[L(x)],tr[R(x)]);
}
void pushdown(int x)
{
	mn[L(x)]-=lz[x];
	mn[R(x)]-=lz[x];
	lz[L(x)]+=lz[x];
	lz[R(x)]+=lz[x];
	lz[x]=0;
}
void add1(int x,int l,int r,int k,int w)
{
	if(l==r)
	{
		q[l].push_back(w);
		if(q[l].size()==1)
		{
			mn[x]=e[q[l].front()].key;
			tr[x]=make_pair(e[q[l].front()].key,e[q[l].front()].val);
			id[x]=l;
		}
		return;
	}
	int mid=(l+r)>>1;
	if(k<=mid)add1(L(x),l,mid,k,w);
	else add1(R(x),mid+1,r,k,w);
	pushup(x);
}
void add2(int x,int l,int r,int L,int R)
{
	if(L>R)return;
	if(r<L||R<l)return;
	if(L<=l&&r<=R)
	{
		mn[x]--;
		lz[x]++;
		return;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	add2(L(x),l,mid,L,R);
	add2(R(x),mid+1,r,L,R);
	pushup(x);
}
void del(int x,int l,int r,int k)
{
	if(l==r)
	{
		q[l].pop_front();
		if(q[l].size()&&q[l].front())
		{
			mn[x]=e[q[l].front()].key-lz[x];
			tr[x]=make_pair(e[q[l].front()].key,e[q[l].front()].val);
			id[x]=l;
		}
		else
		{
			mn[x]=0x3f3f3f3f;
			tr[x]=make_pair(0x3f3f3f3f,0x3f3f3f3f);
			id[x]=l;
		}
		return;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	if(k<=mid)del(L(x),l,mid,k);
	else del(R(x),mid+1,r,k);
	pushup(x);
}
pair<int,int> ask(int x,int l,int r,int L,int R)
{
	if(r<L||R<l)return make_pair(0x3f3f3f3f,0x3f3f3f3f);
	if(L<=l&&r<=R)return tr[x];
	pushdown(x);
	int mid=(l+r)>>1;
	return min(ask(L(x),l,mid,L,R),ask(R(x),mid+1,r,L,R));
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&e[i].key,&e[i].val);
	sort(e+1,e+n+1,cmp1);
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		if(e[i].val==e[i-1].val)sum++;
		else sum=0;
		ans=ans*min(i,e[i].key+sum)%mod;
	}
	printf("%lld\n",ans);
	sort(e+1,e+n+1,cmp2);
	int lst=-1;
	for(int i=1;i<=n;i++)
	{
		if(e[i].val!=lst)
		{
			lst=e[i].val;
			mp[e[i].val]=++cnt;
		}
	}
	for(int i=1;i<=n;i++)
		add1(1,1,cnt,mp[e[i].val],i);
	for(int i=1;i<=n;i++)
	{
		int res;
		if(mn[1]==1)res=id[1];
		else res=cnt;
		pair<int,int> flag=ask(1,1,cnt,1,res);
		printf("%d %d\n",flag.first,flag.second);
		del(1,1,cnt,mp[flag.second]);
		add2(1,1,cnt,1,mp[flag.second]-1);
	}
	return 0;
}

T3

题解

先来考虑确定了所有边权之后如何判定,无非就是当$dis(1\sim i)+dis(i\sim n)=dis(1\sim n)$。

好吧我没打正解……

枚举所有本来就有的边的边权即可,不要忘了$0$和$inf$。

时间复杂度:$\Theta(n\times m\times \log n)$。

代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to,w;}e[5000];
int head[1001],cnt;
int n,m;
long long disf[1001],disr[1001];
bool vis[1001];
long long que[2001];
bool ans[1001];
priority_queue<pair<long long,int>,vector<pair<long long,int>>,greater<pair<long long,int>>>q;
void add(int x,int y,int w)
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	e[cnt].w=w;
	head[x]=cnt;
}
void Dijf(int w)
{
	memset(disf,0x3f,sizeof(disf));
	memset(vis,0,sizeof(vis));
	q.push(make_pair(0,1));
	disf[1]=0;
	while(!q.empty())
	{
		int x=q.top().second;
		q.pop();
		if(vis[x])continue;
		vis[x]=1;
		for(int i=head[x];i;i=e[i].nxt)
		{
			if(disf[e[i].to]>disf[x]+(e[i].w==-1?w:e[i].w))
			{
				disf[e[i].to]=disf[x]+(e[i].w==-1?w:e[i].w);
				q.push(make_pair(disf[e[i].to],e[i].to));
			}
		}
	}
}
void Dijr(int w)
{
	memset(disr,0x3f,sizeof(disr));
	memset(vis,0,sizeof(vis));
	q.push(make_pair(0,n));
	disr[n]=0;
	while(!q.empty())
	{
		int x=q.top().second;
		q.pop();
		if(vis[x])continue;
		vis[x]=1;
		for(int i=head[x];i;i=e[i].nxt)
		{
			if(disr[e[i].to]>disr[x]+(e[i].w==-1?w:e[i].w))
			{
				disr[e[i].to]=disr[x]+(e[i].w==-1?w:e[i].w);
				q.push(make_pair(disr[e[i].to],e[i].to));
			}
		}
	}
}
void judge(long long x)
{
	Dijf(x);
	Dijr(x);
	for(int i=1;i<=n;i++)if(disf[i]+disr[i]==disf[n])ans[i]=1;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);add(v,u,w);
		if(w!=-1)que[++que[0]]=w;
	}
	que[++que[0]]=0;que[++que[0]]=0x3f3f3f3f3f3f3f3f;
	for(int i=1;i<=que[0];i++)
		judge(que[i]);
	for(int i=1;i<=n;i++)printf("%d",ans[i]);
	return 0;
}

Day2


T1

题解

找规律发现其实就是$\frac{n^2-1}{9}$。

时间复杂度:$\Theta(T)$。

代码时刻

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
const int qpw=443664157;
long long n;
int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		scanf("%lld",&n);n%=mod;
		printf("%lld\n",(n*n%mod-1)*qpw%mod);
	}
	return 0;
}

T2

又没有打正解……

建两棵$Trie$树,一正一反,将每一个字符串都扔进$Trie$树里,对于$Trie$树上的每一个点记录如下信息:

  $\alpha.$前缀$hash$值。

  $\beta.$深度。

  $\gamma.$前缀节点个数。

将相同深度的节点信息压如一个$vector$即可。

然后枚举字串的中点,即后缀和前缀的分界点,然后在左右分别二分最长可行前后缀,$judge$的时候在当前长度(深度)的$vector$里查找有没有$hash$值相同的即可。

比正解多一个$\log$,但是常数较小,跑的甚至比正解快(也可以用$hash\text{_}map$剪掉这个$\log$)。

时间复杂度:$\Theta(n\log^2n)$。

代码时刻

#include<bits/stdc++.h>
using namespace std;
int m,lenS;
char s[200001],str[200001];
int cnt[]={1,1},trie[2][200001][30];
unsigned long long ed[2][200001];
unsigned long long mod[200001];
unsigned long long S[200001];
vector<pair<unsigned long long,int>> vec[2][200001];
long long ans;
void insertf(char *str)
{
	int len=strlen(str+1),p=1;
	for(int k=1;k<=len;k++)
	{
		int ch=str[k]-'a';
		if(!trie[0][p][ch])
			trie[0][p][ch]=++cnt[0];
		p=trie[0][p][ch];
		ed[0][p]++;
	}
}
void insertr(char *str)
{
	int len=strlen(str+1),p=1;
	for(int k=len;k;k--)
	{
		int ch=str[k]-'a';
		if(!trie[1][p][ch])
			trie[1][p][ch]=++cnt[1];
		p=trie[1][p][ch];
		ed[1][p]++;
	}
}
void dfsf(int x,int d,unsigned long long hash)
{
	for(int i=0;i<26;i++)
		if(trie[0][x][i])
		{
			ed[0][trie[0][x][i]]+=ed[0][x];
			vec[0][d+1].push_back(make_pair(hash*131+i+1,ed[0][trie[0][x][i]]));
			dfsf(trie[0][x][i],d+1,hash*131+i+1);
		}
}
void dfsr(int x,int d,unsigned long long hash)
{
	for(int i=0;i<26;i++)
		if(trie[1][x][i])
		{
			ed[1][trie[1][x][i]]+=ed[1][x];
			vec[1][d+1].push_back(make_pair(hash+mod[d]*(i+1),ed[1][trie[1][x][i]]));
			dfsr(trie[1][x][i],d+1,hash+mod[d]*(i+1));
		}
}
long long judgef(int mid,int x)
{
	if(!vec[0][mid].size())return 0;
	pair<unsigned long long,int> w=make_pair(S[x+mid-1]-S[x-1]*mod[mid],0);
	int flag=lower_bound(vec[0][mid].begin(),vec[0][mid].end(),w)-vec[0][mid].begin();
	if(vec[0][mid][flag].first==S[x+mid-1]-S[x-1]*mod[mid])return vec[0][mid][flag].second;
	return 0;
}
long long judger(int mid,int x)
{
	if(!vec[1][mid].size())return 0;
	pair<unsigned long long,int> w=make_pair(S[x]-S[x-mid]*mod[mid],0);
	int flag=lower_bound(vec[1][mid].begin(),vec[1][mid].end(),w)-vec[1][mid].begin();
	if(vec[1][mid][flag].first==S[x]-S[x-mid]*mod[mid])return vec[1][mid][flag].second;
	return 0;
}
long long findf(int x)
{
	int lft=1,rht=lenS-x+1;
	long long res=0;
	while(lft<=rht)
	{
		int mid=(lft+rht)>>1;
		long long flag=judgef(mid,x);
		if(flag){res=flag;lft=mid+1;}
		else rht=mid-1;
	}
	return res;
}
long long findr(int x)
{
	int lft=1,rht=x;
	long long res=0;
	while(lft<=rht)
	{
		int mid=(lft+rht)>>1;
		long long flag=judger(mid,x);
		if(flag){res=flag;lft=mid+1;}
		else rht=mid-1;
	}
	return res;
}
int main()
{
	mod[0]=1;for(int i=1;i<=200000;i++)mod[i]=mod[i-1]*131;
	scanf("%s%d",str+1,&m);
	lenS=strlen(str+1);
	for(int i=1;i<=lenS;i++)S[i]=S[i-1]*131+str[i]-'a'+1;
	for(int i=1;i<=m;i++)
	{
		scanf("%s",s+1);
		insertf(s);
		insertr(s);
	}
	dfsf(1,0,0);
	dfsr(1,0,0);
	for(int i=1;i<=200000;i++)
	{
		if(vec[0][i].size())sort(vec[0][i].begin(),vec[0][i].end());
		if(vec[1][i].size())sort(vec[1][i].begin(),vec[1][i].end());
	}
	for(int i=1;i<lenS;i++)
		ans+=findr(i)*findf(i+1);
	printf("%lld",ans);
	return 0;
}

T3

题解

需要分类讨论。

注意不要炸$long\ long$即可。

时间复杂度:$\Theta(\log_{mod}n)$。

代码时刻

#include<bits/stdc++.h>
using namespace std;
const int mod=300007;
long long n,m,k;
long long fac[mod],inv[mod];
long long ans;
long long qpow(long long x,long long y)
{
	long long res=1;
	while(y)
	{
		if(y&1)res=res*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return res;
}
void pre_work()
{
	fac[0]=1;
	for(int i=1;i<mod;i++)fac[i]=fac[i-1]*i%mod;
	inv[mod-1]=qpow(fac[mod-1],mod-2);
	for(int i=mod-1;i;i--)inv[i-1]=inv[i]*i%mod;
}
long long lucas(long long x,long long y)
{
	if(x<y)return 0;
	return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
long long C(long long x,long long y)
{
	if(x<y)return 0;
	if(!y)return 1;
	return lucas(x%mod,y%mod)*C(x/mod,y/mod)%mod;
}
long long get1(long long x){return (2*x%mod*x%mod*x%mod+3*x%mod*x%mod+x)%mod*qpow(6,mod-2)%mod;}
long long get2(long long x){return (x*(x+1))>>1;}
long long work0(){return((C(n,k)*(m%mod)%mod+C(m,k)*(n%mod)%mod)%mod+2*C(m+1,k+1)+2*C(m,k)*((n-m)%mod)%mod+2*C(m,k+1)%mod)%mod;}
long long work1(){return n%mod*(m%mod)%mod;}
void work2(){}
long long work3()
{
	long long X=(min(n+1,(m+2)>>1)-1)%mod;
	long long Y=(min(m+1,(n+2)>>1)-1)%mod;
	n%=mod;m%=mod;
	return (2*(n*m%mod*(X+Y)%mod+2*(get1(X)+get1(Y))%mod-(2*n+m)*get2(X)%mod-(2*m+n)*get2(Y)%mod+mod)%mod+4*(n*m%mod*(m-1)%mod+get1(m-1)-(n+m)*get2(m-1)%mod+mod)%mod+mod)%mod;
}
long long work4()
{
	long long X=(min(n+1,(m+2)>>1)-1)%mod;
	long long Y=(min(m+1,(n+2)>>1)-1)%mod;
	long long Z=(m>>1)%mod;n%=mod;m%=mod;
	return (2*(n*m%mod*(X+Y)%mod+2*(get1(X)+get1(Y))%mod-(2*n+m)*get2(X)%mod-(2*m+n)*get2(Y)%mod+mod)%mod+(n*m%mod*(m-1)%mod+get1(m-1)-(n+m)*get2(m-1)%mod+mod)%mod+5*(n*m%mod*Z%mod-2*(n+m)*get2(Z)%mod+4*get1(Z)+mod)%mod+mod)%mod;
}
long long work5()
{
	long long X=((m-1)>>1)%mod;
	n%=mod;m%=mod;
	return (2*n*m%mod*X%mod+8*get1(X)%mod-4*(n+m)%mod*get2(X)%mod+mod)%mod;
}
void work6(){}
int main()
{
	pre_work();
	int T;scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld%lld",&n,&m,&k);
		if(n<m)n^=m^=n^=m;
		if(k>1)ans=work0();
		switch(k)
		{
			case 1:ans=work1();break;
			case 2:work2();break;
			case 3:ans=(ans+work3())%mod;break;
			case 4:ans=(ans+work4())%mod;break;
			case 5:ans=(ans+work5())%mod;break;
			default:work6();
		}
		printf("%lld\n",ans);
	}
	return 0;
}

最后声明:此博客中涉及的试题题面高度保密,请勿滥用此博客

猜你喜欢

转载自www.cnblogs.com/wzc521/p/11723795.html