省选模拟27
联赛后第一次rk1吧!?还挺激动的
开场发现checker是exe,人傻了,于是我就想要换windows,然而没换成因为windows没有g++
于是万能的水哥出场了,把exe转成了linux下的可执行文件!!!
第一题开场想到了根号的构造方法,最后搞到了正解
第二题看了一会就走了,这玩意实在是不可做
第三题没多久就想到了是状压dp,可以叫插头dp?写的时候细节多得很,一一直写到了11点30,那时的我认为11点50结束考试,给我紧张坏了,11点44的时候4*4的样例都过不了,于是我放弃了,花了2分钟打了个暴力就交上去了
交完之后发现woc12点10分结束!!然后继续调,揪出来两个小错误,然后就切掉了
T1 分裂
一开始想的是我每一层只拿一个下去,最后二进制拆分一下,这样是根号的
然后想一层只剩下一个,剩下的都拿下去,然后发现这样不可行
于是想到了一个折半的做法,每层拿下一半去!!哈哈哈,我可真是个天才
发现最后一层剩下的那一半可以下放两层,这样一定可以满足条件,最后二进制拆分微调就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
return s*t;
}
const int N=1e7+5;
int T,n,buc[30],gx[30],all[30],ans[30];
signed main(){
freopen("split.in","r",stdin);
freopen("split.out","w",stdout);
int now=1;
gx[1]=1;all[1]=1;
fo(i,2,25){
all[i]=all[i-1]-(now+1>>1);
buc[i-1]=(now>>1);
now=((now+1)>>1)*i;
gx[i]=now;
all[i]+=gx[i];
}
T=read();
while(T--){
n=read();
if(n==1){printf("1\n1 1\n");continue;}
if(n==3||n==5||n==8){printf("-1\n");continue;}
memset(ans,0,sizeof(ans));
fo(nn,1,25)if(n<all[nn]){nn-=1;
int ys=n-all[nn];
fo(i,1,nn-1)ans[i]=buc[i];
ans[nn]=gx[nn];ans[0]=nn;
if(ys>ans[nn-1]*(nn-1)){
ans[0]=nn+1;ys-=ans[nn-1]*(nn-1);
ans[nn]+=ans[nn-1]*nn;ans[nn-1]=0;
if(ys>=nn){
ans[nn+1]+=ys/nn*(nn+1);ans[nn]-=ys/nn;
ys%=nn;
}
}
else if(ys>=nn-1){
ans[nn]+=ys/(nn-1)*nn;ans[nn-1]-=ys/(nn-1);
ys%=(nn-1);
}
fu(i,ans[0],1)if(ys>=i&&ans[i]){
ans[i]--;ans[i+1]+=i+1;
ys-=i;ans[0]=max(ans[0],i+1);
}
if(ys){
fo(i,2,ans[0]-1)if(ans[i+1]>i+1){
ans[i]++;ans[i+1]-=i+1;
ans[i+1]--;ans[i+2]+=i+2;
ans[0]=max(ans[0],i+2);
break;
}
}
int res=0;
fo(i,1,ans[0])if(ans[i])res++;
printf("%lld\n",res);
fo(i,1,ans[0])if(ans[i])printf("%lld %lld\n",i,ans[i]);
break;
}
}
return 0;
}
T2 未来
遇到这种题,先想想怎么能把这玩意转化成运算,因为只有算数题才能加速,并且找到可以简化的地方
于是我们给每个字符映射到0,1,2上,发现变换就是\(a_i=(a_i+a_{i+1})*2\%3\)
于是这个东西我们依旧不知道怎么做,但是发现好像一层一层的展开最后是个杨辉三角
想到组合数,发现是对3取模,lucas定理,我们每次转移三进制的某一位,就是\(3^k \choose i\),这样i只有两位是有值的0和\(3^k\)
于是有了logm的做法
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
return s*t;
}
const int N=5e5+5;
char ch[N];
int n,m,a[N],b[N];
signed main(){
freopen("future.in","r",stdin);
freopen("future.out","w",stdout);
n=read();m=read();
scanf("%s",ch);
fo(i,0,n-1){
if(ch[i]=='r')a[i]=0;
else if(ch[i]=='g')a[i]=1;
else a[i]=2;
}
while(m){
int stp=1;
while(stp<=m/3)stp*=3;
while(m>=stp){
fo(i,0,n-1)b[i]=(a[i]+a[(i+stp)%n])*2%3;
fo(i,0,n-1)a[i]=b[i];m-=stp;
}
}
fo(i,0,n-1)printf("%c",a[i]?(a[i]==2?'b':'g'):'r');
}
T3 回忆
直接状压dp,由于宽度最大是6,最多的联通块个数是3,可以4进制压位,压成12位
用map记录每一个联通块的大小,以及历史最大值,转移就行了
细节贼多!!!
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
int s=0,t=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
return s*t;
}
const int N=41;
const int mod=998244353;
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=1ll*ret*x%mod;
x=1ll*x*x%mod;y>>=1;
}return ret;
}
int n,m,jz[N][N],ans;
struct node{
int a[5];
node(){memset(a,0,sizeof(a));}node(int x,int y,int z,int w=0){a[1]=x;a[2]=y;a[3]=z;a[4]=max(w,max(a[1],max(a[2],a[3])));}
bool operator < (node x)const{
if(a[1]!=x.a[1])return a[1]<x.a[1];
if(a[2]!=x.a[2])return a[2]<x.a[2];
if(a[3]!=x.a[3])return a[3]<x.a[3];
return a[4]<x.a[4];
}
};
map<node,int> dp[N][1<<12];
int fai[15],bai[15],zti[15],bti[15];
int find(int x){return fai[x]==x?x:fai[x]=find(fai[x]);}
int get(int s,int i){return (s>>(i-1)*2)&3;}
int bia[15];
signed main(){
freopen("memory.in","r",stdin);
freopen("memory.out","w",stdout);
n=read();m=read();
if(n>m)fo(i,1,n)fo(j,1,m)jz[i][j]=read();
else {
fo(i,1,n)fo(j,1,m)jz[j][i]=read();
swap(n,m);
}
dp[0][0][node(0,0,0,0)]=1;
int u=(1<<m*2)-1;
fo(x,1,n){
fo(s,0,u){
if(dp[x-1][s].size()==0)continue;
fo(i,1,m)fai[i]=bai[i]=i,zti[i]=1<<get(s,i);
fo(i,m+1,2*m)fai[i]=bai[i]=i,zti[i]=0;
fo(i,1,m)fo(j,i+1,m){
if(get(s,i)==get(s,j)){
int fx=find(i),fy=find(j);
if(fx==fy)continue;
fai[fy]=fx;zti[fy]|=zti[fx];
}
}
fo(i,1,2*m)bai[i]=fai[i],bti[i]=zti[i];
for(pair<node,int> o:dp[x-1][s]){
if(!o.second)continue;
fo(t,0,(1<<m)-1){
fo(i,1,2*m)fai[i]=bai[i],zti[i]=bti[i],bia[i]=0;
int las=0,num=0,ss=0;node res=node(0,0,0,o.first.a[4]);
fo(i,1,m+1)if(!((t>>i-1)&1)){
if(las+1>i-1){las=i;continue;}
fo(j,las+1,i-1){
if(!get(s,j))continue;
int fx=find(j+m),fy=find(j);
if(fx==fy)continue;
fai[fx]=fy;zti[fy]|=zti[fx];
}
fo(j,las+1,i-2){
int fx=find(j+m),fy=find(j+m+1);
if(fx==fy)continue;
fai[fx]=fy;zti[fy]|=zti[fx];
}las=i;
}
fo(i,1,m){
if(!((t>>i-1)&1))continue;
if(!bia[find(i+m)]){
bia[find(i+m)]=++num;
fo(j,1,3)if((zti[find(i+m)]>>j)&1){
res.a[bia[find(i+m)]]+=o.first.a[j];
}
}
ss|=(1<<(i-1)*2)*bia[find(i+m)];
res.a[bia[find(i+m)]]++;
}
res.a[4]=max(res.a[4],max(res.a[1],max(res.a[2],res.a[3])));
int gl=1;
fo(i,1,m){
if((t>>i-1)&1)gl=1ll*gl*jz[x][i]%mod;
else gl=1ll*gl*(mod+1-jz[x][i])%mod;
}
if(!gl)continue;
dp[x][ss][node(res)]=(dp[x][ss][node(res)]+1ll*o.second*gl%mod)%mod;
}
}
}
}
fo(s,0,u){
for(pair<node,int> o:dp[n][s]){
int mx=o.first.a[4];
ans=(ans+1ll*mx*o.second%mod)%mod;
}
}
printf("%lld",ans);
return 0;
}
QQ:2953174821