csp-s模拟11
A
题面
注意如果\(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
题面
最暴力的做法,枚举连续段长度\(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)\)的方案数
考虑计算
考虑枚举分成\(j\)段
如果没有\(<=i\)的限制,插空法可知为\(C(n-1,j-1)\)
但是有限制,考虑容斥,钦定有\(k\)个元素\(>i\),因为不能有空,则下界为\(i\),则有\(k\)个元素\(>i\),这时候再插空的话,为\(C(n-ik-1,j-1)\)
把\(k\)枚举提前
美化一下
发现必须满足\(k+ik<=n\)所以枚举\(k\)是调和级数的复杂度
考虑后面部分的组合意义
从\(n-ik\)中选\(j\)个,再从\(j\)个中选\(k\)个,再从\(j\)个中选一个特殊的,再将剩下的\(j-1\)个染成\(m-1\)种颜色
分两种情况,
一种\(k\)中选一个特殊的,对于剩下的染色有\((m-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