返回顶部

csp-s模拟11

A

题面

image

image

image

注意如果\(x_a==x_b\)\(y_a==y_b\)另外一对坐标必须相邻

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 1e3+5,mod=1e9+7,INF=1E9;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
int n,m;
inline int get(int i,int j)
{
	return (i-1)*m+j;
}
int fa[N*N];
inline int find(int u)
{
	if(fa[u]!=u)fa[u]=find(fa[u]);
	return fa[u];
}
inline void un(int u,int v)
{
	u=find(u);v=find(v);
	if(u!=v)fa[u]=v;
}
char s[N][N];
std::vector<int> edge[N];
std::vector<pii> v;
int main()
{
	// file("a");
	freopen("water.in","r",stdin);freopen("water.out","w",stdout);
	int T=read();
	while(T--)
	{
		n=read();m=read();
		v.clear();memset(s,0,sizeof s);
		for(int i=1;i<=n;i++)__builtin_scanf("%s",s[i]+1);
		
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(s[i][j]==s[i+1][j-1]&&i+1<=n&&j>1)
				{
					v.pb({i,j});
				}
			}
		}
		sort(v.begin(), v.end());
		bool f=0;
		for(int i=0;i<v.size();i++)
		{
			auto A=v[i];
			for(int j=i+1;j<v.size();j++)
			{
				auto B=v[j];
				if(A.first==B.first&&A.second==B.second)continue;
				if(A.first<B.first&&A.second<B.second){f=1;break;}
				if(A.first==B.first&&B.second-A.second==1){f=1;break;}
				if(A.first==B.first-1&&B.second-A.second==0){f=1;break;}
			}
		}
		if(f)puts("1");
		else puts("0");
	}
	return 0;
}

C

题面
![image](https://img2024.cnblogs.com/blog/3332334/202410/3332334-20241014193117942-679225921.png)

![image](https://img2024.cnblogs.com/blog/3332334/202410/3332334-20241014193133396-1406026594.png)


暴力,搜索

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 1e5+5,mod=1e9+7,INF=1E9;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
ll n,k,a[N],sum[N],smx[N],smi[N];
ll top;pii stk[N];ll res;
inline void dfs(int now,int cnt)
{
	if(now==n+1)
	{
		if(cnt!=k)return;
		top=0;
		// ts;
		for(int i=1;i<=n;i++)smx[i]=max(smx[i-1],a[i]);
		for(int i=n;i>=1;i--)smi[i]=max(smi[i+1],a[i]);
		ll ans=0;
		for(int i=2;i<n;i++)
		{
			if(smx[i-1]>a[i]&&smi[i+1]>a[i]){
				// cout<<i<<" "<<min(smx[i-1],smi[i+1])-a[i]<<endl;
				ans+=min(smx[i-1],smi[i+1])-a[i];
			}
		}
		// cout<<ans<<endl;
		if(ans%2==0)res++;
		if(res>mod)res-=mod;
		return;
	}
	int tmp=a[now];
	a[now]=0;
	if(cnt+1<=k)dfs(now+1,cnt+1);
	a[now]=tmp;
	dfs(now+1,cnt);
}
int main(int argc, char const *argv[])
{
	// file("a");
	freopen("rain.in","r",stdin);freopen("rain.out","w",stdout);
	n=read();k=read();
	for(int i=1;i<=n;i++)a[i]=read();
	dfs(1,0);
	write(res);
	return 0;
}

考虑\(k\)很小,也就是铲平的地很少,由于至多会去掉 \(K\) 块土地,所以对于任意一个 \(i,j\) 的值只有 \(K+1\) 种(最大值改变最多\(k\)次)。
正解,奇妙\(DP\),设\(dp_{i,k,0/1,j}\)表示前\(i\)位,铲平了\(k\),\(0/1\)积水为偶数/奇数 最大高度为位置为\(j\),考虑前缀做一遍,后缀做一遍,最后合并起来,我们可以预处理出每一段前\(k+1\)大的数,然后映射为位置,方便转移,转移很简单
细节:
1. \(k=1\)的时候直接特判即可
2. 转移初始化因为相对位置第一位最小为\(0\)映射值为1,所以实际为\(dp_{1/n,0,0,2}=1\),还有如果\(k>0,dp_{1/n,1,0,1}=1\)表示铲平了\(h_1\),映射位置为\(2\)

如何合并答案,相当于枚举最大值的位置\(i\),然后前缀后缀合并,但是为了不计算重复规定一边\(<=h_i\)一边\(<h_i\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 40000+5,INF=1E9,mod=1e9+7;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
int n,k,h[N];
multiset <int> s;
int pre[N][29],pn[N],low[N][29];
int nxt[N][29],nn[N],row[N][29];
int f[N][27][2][27],g[N][27][2][27];
//前i个 铲平了k 积水为偶数/奇数 最大高度为位置为j
inline void add(int &u,int v)
{
	// cout<<u<<" "<<v<<endl;
	u+=v;
	u=u>=mod?u-mod:u;
	return ; 
}
inline ll mul(ll u,ll v)
{
	return 1ll*u*v%mod;
}
int main()
{
	file("a");
	// freopen("rain.in","r",stdin);freopen("rain.out","w",stdout);
	n=read();k=read();
	for(int i=1;i<=n;i++)h[i]=read();
	if(n == 1 && k == 0){
		write(1);
		return 0;
	}
	s.insert(0);
	for(int i=1;i<=n;i++)
	{
		s.insert(h[i]);
		while(s.size()>k+1)s.erase(s.begin());
		for(int x:s)pre[i][++pre[i][0]]=x;
	}
	for(int i=1;i<n;i++)
	{
		pn[i+1]=lower_bound(pre[i+1]+1,pre[i+1]+1+pre[i+1][0],h[i+1])-pre[i+1];
		// cout<<pn[i+1]<<endl;
		for(int j=1;j<=pre[i][0];j++){
			low[i][j]=lower_bound(pre[i+1]+1,pre[i+1]+1+pre[i+1][0],pre[i][j])-pre[i+1];
		}
	}
	f[1][0][0][2]=1;
	if(k)f[1][1][0][1]=1;
	for(int i=1;i<n;i++)
	{
		int mk=min(i,k);
		for(int nk=0;nk<=mk;nk++)
		{
			for(int op=0;op<=1;op++)
			{
				for(int m=1;m<=pre[i][0];m++)
				{
					if(f[i][nk][op][m])
					{
						int hi=pre[i][m],ct=f[i][nk][op][m],po=low[i][m];
						if(nk<k)add(f[i+1][nk+1][(op+hi)&1][po],ct);
						if(h[i+1]<hi)add(f[i+1][nk][(op+hi-h[i+1])&1][po],ct);
						else add(f[i+1][nk][op][pn[i+1]],ct);
					}
				}
			}
		}
	}
	s.clear();
	s.insert(0);
	for(int i=n;i>=1;i--)
	{
		s.insert(h[i]);
		while(s.size()>k+1)s.erase(s.begin());
		for(int x:s)nxt[i][++nxt[i][0]]=x;
	}
	for(int i=n;i>1;i--)
	{
		nn[i-1]=lower_bound(nxt[i-1]+1,nxt[i-1]+1+nxt[i-1][0],h[i-1])-nxt[i-1];
		for(int j=1;j<=nxt[i][0];j++)
			row[i][j]=lower_bound(nxt[i-1]+1,nxt[i-1]+1+nxt[i-1][0],nxt[i][j])-nxt[i-1];
	}	
	g[n][0][0][2]=1;
	if(k)g[n][1][0][1]=1;
	for(int i=n;i>1;i--)
	{
		int mk=min(n-i+1,k);
		for(int nk=0;nk<=mk;nk++)
		{
			for(int op=0;op<=1;op++)
			{
				for(int m=1;m<=nxt[i][0];m++)
				{
					if(g[i][nk][op][m])
					{
						int hi=nxt[i][m],ct=g[i][nk][op][m],po=row[i][m];
						if(nk<k)add(g[i-1][nk+1][(op+hi)&1][po],ct);
						if(h[i-1]<hi)add(g[i-1][nk][(op+hi-h[i-1])&1][po],ct);
						else add(g[i-1][nk][op][nn[i-1]],ct);

					}
				}
			}
		}
	}	
	ll ans=0;
	for(int i=1;i<=pre[n-1][0];i++)if(pre[n-1][i]<=h[n])ans+=f[n-1][k][0][i];else break;
	for(int i=1;i<=nxt[2][0];i++)if(nxt[2][i]<h[1])ans+=g[2][k][0][i];else break;
	// cout<<ans<<endl;
	for(int i=2;i<n;i++)
	{
		for(int kl=0;kl<=k;kl++)
		{
			int kr=k-kl;
			int sl0=0,sl1=0;
			for(int j=1;j<=pre[i-1][0];j++)
				if(pre[i-1][j]<=h[i]){
					add(sl0,f[i-1][kl][0][j]);
					add(sl1,f[i-1][kl][1][j]);
				}else break;
			int sr0=0,sr1=0;
			for(int j=1;j<=nxt[i+1][0];j++)
				if(nxt[i+1][j]<h[i])
				{
					add(sr0,g[i+1][kr][0][j]);
					add(sr1,g[i+1][kr][1][j]);					
				}else break;
			ans+=mul(sl0,sr0);
			ans+=mul(sl1,sr1);
		}
	}
	write(ans%mod);
	return 0;
}

E

题面

image

最暴力的做法,枚举连续段长度\(i\),然后暴力搜索,复杂度\(O(n^3)\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 5000+5,INF=1E9;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
ll mod;
ll n,m;
ll dp[N][N];ll tot;
inline ll work(int len,int id,int mx)
{
	if(dp[len][mx])return dp[len][mx];
	if(id>mx&&len<id)return 0;
	if(!len)return mx==id;
	ll ans=0;
	// cout<<(m-(len==n))<<endl;
	for(int i=1;i<=min(len,id);i++)
	{
		ans=(ans+ work( len-i,id,max(mx,i) )*(m-(len!=n))%mod )%mod;
	}
	// cout<<id<<" "<<ans<<endl;
	return dp[len][mx]=ans;
}
int main(int argc, char const *argv[])
{
	file("a");
	// freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);
	n=read();m=read();mod=read();
	for(ll i=1;i<=n;i++)
	{
		// cout<<work(n,i,0)<<endl;
		for(int j=0;j<=n;j++)
			for(int k=0;k<=i;k++)dp[j][k]=0;
		tot+=work(n,i,0)*i%mod;
		// ts;
		tot%=mod;
	}
	write(tot);
	return 0;
}
//10 2 998244353
//100 23333333 998244353

枚举\(<=x\)的方案数 ,考虑\(dp_i\)长度为\(i\)时,可以从\([i-x,i-1]\)转移过来,当然\([i<=x]\)也可以直接从\(0\)转移过来,然后前缀和优化,复杂度\(O(n^2)\),感谢\(lhx\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 5000+5,INF=1E9;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
ll mod;
ll n,m;
ll dp[N];ll tot;
ll sum[N];ll ans[N];
int main(int argc, char const *argv[])
{
	// file("a");
	freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);
	n=read();m=read();mod=read();
	for(int x=1;x<=n;x++)
	{
		dp[1]=m;sum[1]=m;
		for(int i=2;i<=n;i++)
		{
			int ls=max(0,i-x-1);
			dp[i]=(m*(i<=x)+(sum[i-1]-sum[ls]+mod)%mod*(m-1)%mod)%mod;
			sum[i]=(sum[i-1]+dp[i])%mod;
			// cout<<dp[i]<<endl;
		}
		ans[x]=dp[n];
		// cout<<dp[n]<<endl;
	}
	ll val=0;
	for(int i=1;i<=n;i++)
	{
		val+=(ans[i]-ans[i-1]+mod)%mod*i%mod;
		val%=mod;
	}
	write(val);
	return 0;
}
//10 2 998244353
//100 23333333 998244353

考虑优化,
设$$ans=\sum_{i=1}^n方案数(len=i)\times i$$
\(F(len<i)\)的方案数

\[ans=\sum_{i=1}^nF(len>=i) \]

\[ans=\sum_{i=1}^n (m^n -F(len<i)) \]

考虑计算

\[\sum_{i=0}^{n-1}F(len<=i) \]

考虑枚举分成\(j\)
如果没有\(<=i\)的限制,插空法可知为\(C(n-1,j-1)\)
但是有限制,考虑容斥,钦定有\(k\)个元素\(>i\),因为不能有空,则下界为\(i\),则有\(k\)个元素\(>i\),这时候再插空的话,为\(C(n-ik-1,j-1)\)

\[\sum_{i=0}^{n-1}\sum_{j=0}^{n}m\times (m-1)^{j-1}\sum_{k=0}^j(-1)^kC(j,k)C(n-ik-1,j-1) \]

\(k\)枚举提前
美化一下

\[m\times \sum_{i=0}^{n-1} \sum_{k=0}^n(-1)^k\frac{1}{n-ik} \sum_{j=k}^{n} (m-1)^{j-1}C(j,k)C(n-ik,j)j \]

发现必须满足\(k+ik<=n\)所以枚举\(k\)是调和级数的复杂度
考虑后面部分的组合意义
\(n-ik\)中选\(j\)个,再从\(j\)个中选\(k\)个,再从\(j\)个中选一个特殊的,再将剩下的\(j-1\)个染成\(m-1\)种颜色
分两种情况,
一种\(k\)中选一个特殊的,对于剩下的染色有\((m-1+不染)=m\)
一种在\(n-ik-k\)中选一个特殊的

\[\sum_{j=k}^{n} (m-1)^{j-1}C(j,k)C(n-ik,j)j=C(n-ik,k)((m-1)^k(n-ik-k)m^{n-ik-k-1}+k(m-1)^{k-1}m^{n-ik-k}) \]

复杂度\(O(n\log n)\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 3e5+5,INF=1E9;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
ll mod;
ll n,m;
ll tot;
inline ll qpow(ll a, ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		a=a*a%mod;b>>=1;
	}
	return ans;
}
ll m1[N],mm[N],jie[N],inv[N];
inline ll C(int n,int m)
{
	return jie[n]*inv[m]%mod*inv[n-m]%mod;
}
// #define int long long
ll iv[N];
signed main()
{
	// file("a");
	freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);
	n=read();m=read();mod=read();
	ll ans=0;
	m1[0]=mm[0]=1;
	for(int i=1;i<=n;i++)m1[i]=m1[i-1]*(m-1)%mod,mm[i]=mm[i-1]*m%mod;
	jie[0]=1;inv[0]=1;
	for(int i=1;i<=n;i++)jie[i]=jie[i-1]*i%mod;
	inv[n]=qpow(jie[n],mod-2);
	for(int i=n-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
	iv[1]=1;
	for(int i=2;i<=n;i++)
	{
		iv[i]=(mod-mod/i)*iv[mod%i]%mod;
	}
	for(ll i=0;i<=n-1;i++)
	{
		ll cnt=1;ll val=0;
		for(ll k=0;i*k+k<=n;k++)
		{
			// if(n-i*k-k-1<0)break;
			val=(val+ cnt*iv[n-i*k]*( m1[k]%mod*(n-i*k-k)%mod*mm[max<int>(n-i*k-k-1,0)]%mod+k*m1[k-1]%mod*mm[n-i*k-k]%mod )%mod*C(n-i*k,k)%mod )%mod;
			val=(val+mod)%mod;
			// val=val*C(n-i*k,k)%mod;
			cnt=-cnt;
		}
		ans=(ans+val)%mod;
	}
	ans=ans*m%mod;
	ans=(n*mm[n]%mod-ans+mod)%mod;
	write(ans);
	return 0;
}
//10 2 998244353
//100 23333333 998244353
posted @ 2024-10-14 16:30  wlesq  阅读(58)  评论(4编辑  收藏  举报