省選模擬27
阿新 • • 發佈:2022-03-07
聯賽後第一次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;
}