省选模拟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;
}