一轮省集 day1

等晚自习再详细写一下。

upd:晚自习太累了。

\(80+20+0=100\),去掉外省以后是 rk16,这下 D1 了。

T1 和 T2 都是沿着正解角度去想的,T1 就差一步了,T2 想的就是正解不过没看见数据随机没敢写,很遗憾。

策略大概没啥问题吧,开场做四个小时 T1 感觉还是太菜了。其它没啥问题,除了最后一步没想到。

T1

首先场上感受了一下充要条件,形如若干个长度为 \(r\)\(c\) 的段的和要相同,进一步可以感受出形如模意义下 \((i,j)\) 矩阵的差分矩阵必须右下角全为 \(0\),这是必要的,但是场上误以为这也是充分的,写了以后发现并非充分。实际上只需进一步保证前 \(r\) 行和前 \(c\) 列的性质就是充要的了,场上对这个容斥预处理做到了 \(O(4^{rc})\)

zyf 讲的角度更好刻画,但是他这个 \(O(3^{rc})\) 咋做的啊?


太闲了,写一下我是怎么容斥的。

\(s[(a,b),(c,d)]\) 代表矩形和。一定有 \(s[(1,1),(1,c)]=s[(r+1,1),(r+1,c)]\) 之类的东西成立,进一步推广得到 \(a_{r+1,1}-a_{1,1}=a_{r+1,c+1}-a_{1,c+1}\),感觉后面貌似不太好用自然语言描述了。

赛时代码
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pii std::pair<int,int>
#define vint std::vector<int>
#define vpair std::vector<pii>
#define debug(...) fprintf(stderr,##__VA_ARGS__)

template<typename T>
void read(T &x){
	x=0;
	int f=1;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') x=x*10+(int)(c-'0'),c=getchar();
	x*=f;
}

std::stack<char>st;
template<typename T>
void print(T x){
	if(x==0) putchar('0');
	if(x<0) putchar('-'),x=-x;
	while(st.size()) st.pop();
	while(x) st.push((char)('0'+x%10)),x/=10;
	while(st.size()) putchar(st.top()),st.pop();
}

template<typename T>
void printsp(T x){
	print(x),putchar(' ');
}

template<typename T>
void println(T x){
	print(x),putchar('\n');
}

template<typename T,typename I>
bool chkmin(T &a,I b){
	if(a>b) return a=b,1;
	return 0;
}

template<typename T,typename I>
bool chkmax(T &a,I b){
	if(a<b) return a=b,1;
	return 0;
}

template<typename T,typename I>
void addedge(std::vector<I>*vec,T u,T v){
	vec[u].push_back(v);
}

template<typename T,typename I,typename K>
void addedge(std::vector<K>*vec,T u,T v,I w){
	vec[u].push_back({v,w});
}

template<typename T,typename I>
void addd(std::vector<I>*vec,T u,T v){
	addedge(vec,u,v),addedge(vec,v,u);
}

template<typename T,typename I,typename K>
void addd(std::vector<K>*vec,T u,T v,I w){
	addedge(vec,u,v,w),addedge(vec,v,u,w);
}

bool Mbe;

const int inf=1e18,MOD1=998244353,MOD2=1e9+7;

int w[5][10][100],n,m,r,c,mod,pw3[15];

void add(int &a,int b){
	a+=b;
	if(a>=mod) a-=mod;
}

int ksm(int x,int y,int p=mod){
	if(y==0) return 1;
	int z=ksm(x,y>>1,p);
	z=z*z%p;
	if(y&1) z=z*x%p;
	return z;
}

int ans;

namespace zhenjianuo2025{
	int a[5],I1,I2,h1[20],h2[20];
	void dfs(int p){
		// debug("p=%lld\n",p);
		int len=p-1;
		if(len!=0){
			int ad=0;
			for(int i=1;i<=len;i++) ad+=a[i];
			for(int i=0;i<(1ll<<len);i++){
				int v=0;
				for(int j=0;j<len;j++){
					if((i&(1<<j))==0){
						v+=2*pw3[j];
						continue;
					}
					if(a[j+1]==0) continue;
					else v+=pw3[j];
				}
				w[len][ad][v]++;
				// debug("len=%lld v=%lld w=%lld\n",len,v,w[len][v]);
			}
			// return ;
		}
		if(len==4) return ;
		a[p]=1,dfs(p+1),a[p]=0,dfs(p+1);
	}
	void init(){
		pw3[0]=1;
		for(int i=1;i<14;i++) pw3[i]=pw3[i-1]*3%mod;
		for(int i=0;i<c;i++) I1+=2*pw3[i];
		for(int i=0;i<r;i++) I2+=2*pw3[i];
		for(int i=1;i<=r;i++){
			int md=i%r;
			h1[i]=n/r;
			if(md<=n%r&&md!=0) h1[i]++;
			// debug("i=%lld h1=%lld\n",i,h1[i]);
		}
		for(int i=1;i<=c;i++){
			int md=i%c;
			h2[i]=m/c;
			if(md<=m%c&&md!=0) h2[i]++;
			// debug("i=%lld h2=%lld\n",i,h2[i]);
		}
		dfs(1);
	}
	int limit[20],d[20][20],sum[40];
	void put3(int x){
		std::stack<int>st;
		while(x){
			st.push(x%3),x/=3;
		}
		while(st.size()) print(st.top()),st.pop();
		putchar('\n');
	}
	int get3(int x,int y){
		for(int i=0;i<y;i++) x/=3;
		return x%3;
	}
	int chg(int x,int y,int z){
		x-=get3(x,y)*pw3[y];
		x+=z*pw3[y];
		return x;
	}
	int g[20][5][110][110],k[15],cnt;
	void init2(){
		//ok we'll init the all limits
		for(int row=1;row<=r;row++){
			//init the row
			for(int tot=0;tot<=c;tot++)
			for(int i=0;i<=I1;i++){
				for(int j=0;j<=I1;j++){
					//if the pos in i is 2 no limit
					//if the pos in j is 2 no limit
					//we'll use rongchi
					cnt=0;
					for(int p=0;p<c;p++){
						if(get3(j,p)==2) continue;
						k[cnt]=p,cnt++;
					}
					g[row][tot][i][j]=ksm(w[c][tot][i],h1[row]-1);
					// cnt--;
					for(int p=1;p<(1<<cnt);p++){
						//qin ding p zhong de bu bei man zu
						int coef=1;
						if(__builtin_popcount(p)&1) coef=-1;
						int state=i;
						for(int pos=0;pos<cnt;pos++){
							if((p&(1<<pos))==0) continue;
							state=chg(state,k[pos],get3(j,k[pos]));
						}
						add(g[row][tot][i][j],(mod+coef*ksm(w[c][tot][state],h1[row]-1))%mod);
					}
					// debug("row=%lld tot=%lld g=%lld h1=%lld cnt=%lld ",row,tot,g[row][tot][i][j],h1[row],cnt),put3(i),put3(j);
				}
			}
		}
		// debug("ok\n");
		for(int col=1;col<=c;col++){
			//init the column
			for(int tot=0;tot<=r;tot++)
			for(int i=0;i<=I2;i++){
				for(int j=0;j<=I2;j++){
					//if the pos in i is 2 no limit
					//if the pos in j is 2 no limit
					//we'll use rongchi
					cnt=0;
					for(int p=0;p<r;p++){
						if(get3(j,p)==2) continue;
						k[cnt]=p,cnt++;
					}
					g[col+r][tot][i][j]=ksm(w[r][tot][i],h2[col]-1);
					// cnt--;
					// debug("col=%lld tot=%lld cnt=%lld\n",col,tot,cnt);
					for(int p=1;p<(1<<cnt);p++){
						//qin ding p zhong de bu bei man zu
						int coef=1;
						if(__builtin_popcount(p)&1) coef=-1;
						int state=i;
						for(int pos=0;pos<cnt;pos++){
							if((p&(1<<pos))==0) continue;
							state=chg(state,k[pos],get3(j,k[pos]));
						}
						// debug("")
						add(g[col+r][tot][i][j],(mod+coef*ksm(w[r][tot][state],h2[col]-1))%mod);
						// debug("col=%lld tot=%lld h2=%lld cnt=%lld \n",col,tot,h2[col],cnt);
					}
				}
			}
		}
		// debug("ok\n");
		return ;
	}
	int nlimit[20];
	bool fl=0;
	void cdfs(int x,int y){
		if(y==c+1) x++,y=1;
		if(x==r+1){
			int f=1;
			for(int i=1;i<=r;i++) {
				f=f*g[i][sum[i]][limit[i]][nlimit[i]]%mod;
				// if(fl)debug("i=%lld sum=%lld g=%lld ",i,sum[i],g[i][sum[i]][limit[i]][nlimit[i]]),put3(limit[i]),put3(nlimit[i]);
			}
			for(int i=1;i<=c;i++){
				f=f*g[i+r][sum[i+r]][limit[i+r]][nlimit[i+r]]%mod;
				// if(fl) debug("i=%lld sum=%lld g=%lld ",i,sum[i+r],g[i+r][sum[i+r]][limit[i+r]][nlimit[i+r]]),put3(limit[i+r]),put3(nlimit[i+r]);
			}
			// if(fl)debug("f=%lld\n",f);
			add(ans,f);
		// if(fl)debug("\n");
			return ;
		}
		if(d[x][y]==0){
			limit[x]-=2*pw3[y-1];
			/*if(!(w[c][sum[x]][limit[x]]==0&&h1[x]>1))*/ cdfs(x,y+1);
			limit[x]+=2*pw3[y-1];
			limit[y+r]-=2*pw3[x-1],nlimit[x]-=2*pw3[y-1];
			/*if(!(w[r][sum[y+r]][limit[x]]==0&&h2[y]>1))*/ cdfs(x,y+1);
			limit[y+r]+=2*pw3[x-1],nlimit[x]+=2*pw3[y-1];
		}else{
			limit[x]-=pw3[y-1];
			/*if(!(w[c][sum[x]][limit[x]]==0&&h1[x]>1))*/ cdfs(x,y+1);
			limit[x]+=pw3[y-1];
			limit[y+r]-=pw3[x-1],nlimit[x]-=pw3[y-1];
			/*if(!(w[r][sum[y+r]][limit[x]]==0&&h2[y]>1))*/ cdfs(x,y+1);
			limit[y+r]+=pw3[x-1],nlimit[x]+=pw3[y-1];
		}
	}
	void print(int n,int m){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++) printsp(d[i][j]);
			putchar('\n');
		}
		putchar('\n');
	}
	bool isis(){
		if(d[1][1]==1&&d[1][2]==0&&d[2][1]==0&&d[2][2]==1&&d[3][1]==1&&d[3][2]==0) return 1;
		return 0;
	}
	void pdfs(int x,int y){
		if(y==c+1) x++,y=1;
		if(x==r+1){
			for(int i=1;i<=r;i++) limit[i]=nlimit[i]=I1;
			for(int i=1;i<=c;i++) limit[i+r]=nlimit[i+r]=I2;
			memset(sum,0,sizeof(sum));
			for(int i=1;i<=r;i++)
				for(int j=1;j<=c;j++) sum[i]+=d[i][j],sum[j+r]+=d[i][j];
			// int las=ans;
			// if(isis()) fl=1;
			cdfs(1,1);
			// if(fl)print(r,c);
			// if(fl)debug("del = %lld ans = %lld\n",ans-las,ans);
			// fl=0;
			return ;
		}
		d[x][y]=1,pdfs(x,y+1),d[x][y]=0,pdfs(x,y+1);
	}
	void solve(){
		init2();
		// debug("ok\n");
		pdfs(1,1);
		println(ans);
	}
}

bool Men;

signed main(){
	//freopen("a.in","r",stdin),freopen("a.out","w",stdout);
	// freopen("data.in","r",stdin),freopen("a.out","w",stdout);
	debug("%.6lfMB\n",(&Mbe-&Men)/1048576.0);
	read(n),read(m),read(r),read(c),read(mod);
	zhenjianuo2025::init(),zhenjianuo2025::solve();
	debug("%.6lfms\n",1e3*clock()/CLOCKS_PER_SEC);
}

T2

转切比雪夫后 \(O(n^2\log n)\) 不需要脑子。

首先性质可以 bitset 做。对其进一步分块就能做整个题了。

T3

这我哪会?

posted @ 2025-03-30 17:19  BYR_KKK  阅读(64)  评论(2)    收藏  举报