省选模拟27

A. 分裂

先给他补到最近的阶乘和最近的阶乘 \(-1\) ,然后再枚举往后的几个都转移几次

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,n,N,res;
int a[30],fac[30],x,cnt;
bool fg;
inline void solve(){
	N=read();x=upper_bound(fac+1,fac+1+20,N)-fac-1;memset(a,0,sizeof(a));cnt=0;n=N-fac[x];
	for(int v1=0;v1<=10;v1++) for(int v2=0;v2<=min(10ll,v1*(x+2));v2++) for(int v3=0;v3<=min(10ll,v2*(x+3));v3++){
		res=n-(v1*(x+1)+v2*(x+2)+v3*(x+3));
		if(res%x==0){
			fg=1;cnt=0;
			a[x]=fac[x]-res/x;
			a[x+1]=res/x*(x+1)-v1;
			a[x+2]=v1*(x+2)-v2;
			a[x+3]=v2*(x+3)-v3;
			a[x+4]=v3*(x+4);
			for(int i=x;i<=x+4;i++) if(a[i]<0) fg=0;
			for(int i=x;i<=x+4;i++) if(a[i]) cnt++;
			if(fg){
				printf("%lld\n",cnt);
				for(int i=x;i<=x+4;i++) if(a[i]) printf("%lld %lld\n",i,a[i]);
				return ;
			}
		}
	}
	x--;memset(a,0,sizeof(a));cnt=0;n=N-fac[x];
	for(int v1=0;v1<=10;v1++) for(int v2=0;v2<=min(10ll,v1*(x+2));v2++) for(int v3=0;v3<=min(10ll,v2*(x+3));v3++){
		res=n-(v1*(x+1)+v2*(x+2)+v3*(x+3));
		if(res%x==0){
			fg=1;cnt=0;
			a[x]=fac[x]-res/x;
			a[x+1]=res/x*(x+1)-v1;
			a[x+2]=v1*(x+2)-v2;
			a[x+3]=v2*(x+3)-v3;
			a[x+4]=v3*(x+4);
			for(int i=x;i<=x+4;i++) if(a[i]<0) fg=0;
			for(int i=x;i<=x+4;i++) if(a[i]) cnt++;
			if(fg){
				printf("%lld\n",cnt);
				for(int i=x;i<=x+4;i++) if(a[i]) printf("%lld %lld\n",i,a[i]);
				return ;
			}
		}
	}
	puts("-1");
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("split.in","r",stdin);
	freopen("split.out","w",stdout);
	fac[0]=1;for(int i=1;i<=20;i++) fac[i]=fac[i-1]*i;
	T=read();while(T--) solve();
	return 0;
}

B. 未来

容易发现给颜色编号后,他们之间的运算关系肯定是 \(\text{mod}\ 3\) 意义下的

赛时看出来的关系是相加再乘 \(2\) 然后模 \(3\)

看出来转移的系数是组合数,但是没想到系数也是可以模 \(3\)

直接做 \(m\) 次,不太好做,于是每 \(3^k\) 做一次转移就行

那么根据 \(Lucas\)\(\text{mod}\ 3\) 意义下取值不为 \(0\) 的只有 \(0\)\(3^k\) ,这样就大大减少了有效位置的数量

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,step=1;
int a[500010],b[500010];
char st[500010];
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("future.in","r",stdin);
	freopen("future.out","w",stdout);
	n=read(),m=read();scanf("%s",st);
	for(int i=0;i<n;i++){
		if(st[i]=='r') a[i]=0;
		if(st[i]=='g') a[i]=1;
		if(st[i]=='b') a[i]=2;
	}
	while(m){
		step=1;
		while(step<=m/3) step*=3;
		while(m>=step){
			m-=step;
			for(int i=0;i<n;i++) b[i]=(a[i]+a[(i+step)%n])*2%3;
			for(int i=0;i<n;i++) a[i]=b[i];
		}
	}
	for(int i=0;i<n;i++){
		if(a[i]==0) putchar('r');
		if(a[i]==1) putchar('g');
		if(a[i]==2) putchar('b');
	}
	return 0;
}

C. 回忆

状压 \(dp\) ,设 \(f_{i,j,k}\) 分别表示每个格子属于的联通块的状态为 \(i\) ,每个联通块的大小状态为 \(j\) ,最大的联通块大小为 \(k\)

没看见 \(n*m\leq 40\) 这个条件,所以没往这个方向上想

假设 \(m\leq n\) 那么 \(m\) 最大为 \(6\)

然后发现有效的状态很少所以用 \(map\) 去转移

Code
#include<bits/stdc++.h>
//#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define mod 998244353
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,U,UU;
long long ans;
int a[50][50],b[50][50],inc[20],id[20];
int fa[20],siz[20],vis[20];
struct data{
	int a[4];
	inline bool operator<(const data &b)const{
		if(a[0]!=b.a[0]) return a[0]<b.a[0];
		if(a[1]!=b.a[1]) return a[1]<b.a[1];
		if(a[2]!=b.a[2]) return a[2]<b.a[2];
		return a[3]<b.a[3];
	}
}tv;
map<data,int>f[42][4100];
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
inline void merge(int x,int y){
	x=getfa(fa[x]);y=getfa(fa[y]);
	if(x==y) return ;
	fa[x]=y;siz[y]+=siz[x];
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("memory.in","r",stdin);
	freopen("memory.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read();
	inc[0]=1;for(int i=1;i<=8;i++) inc[i]=inc[i-1]<<2;
	if(n<m){
		for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) b[j][i]=a[i][j];swap(n,m);memset(a,0,sizeof(a));
		for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=b[i][j];
	}
	f[0][0][(data){0,0,0,0}]=1;U=(1<<(m*2))-1;UU=(1<<m)-1;
	for(int i=1;i<=n;i++) for(int j=0;j<=U;j++) for(auto L:f[i-1][j]){
		for(int sta=0,p,cnt,vs,mk;sta<=UU;sta++){
			mk=L.first.a[0],cnt=0,vs=0,p=1;for(int l=1;l<=m;l++){
				if((sta>>(l-1))&1) p=1ll*p*a[i][l]%mod;
				else p=1ll*p*(1+mod-a[i][l])%mod;
			}
			memset(vis,0,sizeof(vis));memset(id,0,sizeof(id));
			for(int l=1;l<=m+m+5;l++) fa[l]=l,siz[l]=0;
			for(int l=1;l<=m;l++) id[l]=(j>>((l-1)*2))&3;
			for(int l=1;l<=m;l++) if(id[l]) merge(l,id[l]+m+m);
			for(int l=1;l<=m;l++) if(id[l]) siz[getfa(l)]=L.first.a[id[l]];
			for(int l=1;l<=m;l++) if((sta>>(l-1))&1){
				siz[l+m]=1;
				if(id[l]){merge(l,l+m);}
				if((sta>>(l-2))&1){merge(l+m,l+m-1);}
			}
			for(int l=1;l<=m;l++) if((sta>>(l-1))&1){
				if(!vis[getfa(l+m)]) mk=max(mk,tv.a[vis[getfa(l+m)]=++cnt]=siz[getfa(l+m)]);
				vs+=inc[l-1]*vis[fa[l+m]];
			}
			tv.a[0]=mk;(f[i][vs][tv]+=1ll*L.second*p%mod)%=mod;
		}
	}
	for(int j=0;j<=U;j++) for(auto L:f[n][j]) (ans+=1ll*L.first.a[0]*L.second)%=mod;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2022-03-07 17:03  Max_QAQ  阅读(47)  评论(0编辑  收藏  举报