一轮省集 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
这我哪会?