20181025小結-2
阿新 • • 發佈:2018-11-01
Big Barn 巨大的牛棚
棋盤製作
牛線Cow Line
傳紙條
OKR-Periods of Words
【以上均出自WOJ】
Big Barn 巨大的牛棚
矩陣DP
動態規劃
f [ i ] [ j ] = min ( min ( f [ i ] [ j-1] , f [ i - 1 ] [ j ] ) , f [ i - 1 ] [ j - 1 ] ) + 1 ;
f(i, j)表示以(i, j)為右下角的最大正方形的邊長。
此位置上沒種樹時才更新。
通俗易懂
#include<bits/stdc++.h> using namespace std; int n,m,ans=0; int a[1005][1005],f[1005][1005]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y; scanf("%d%d",&x,&y); a[x][y]=1; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(!a[i][j]){//沒樹 f[i][j]=min(min(f[i-1][j-1],f[i-1][j]),f[i][j-1])+1; if(f[i][j]>ans)ans=f[i][j]; } printf("%d",ans); return 0; }
棋盤製作
矩陣DP
動態規劃
懸線法
qwq ^ __ ^ qwq的演算法二:懸線法+上面的最大正方形
* _ *加深印象
先預處理染色一下很重要哦!!!
#include<bits/stdc++.h> using namespace std; int n,m,ans1=0,ans2=0,tmp; int a[2001][2001],f[2001][2001];// void work1(){//正方形 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]){//見WOJ1787 f[i][j]=min(min(f[i-1][j-1],f[i-1][j]),f[i][j-1])+1; if(f[i][j]>ans1)ans1=f[i][j]; } } int l[2001][2001],r[2001][2001];//整個上方矩形左右最近障礙 int dl[2001][2001],dr[2001][2001];//當前行左右最近障礙 () int h[2001][2001];//高度 void work2(){ for(int i=1;i<=n;i++){ tmp=0; for(int j=1;j<=m;j++)//計算左邊最近障礙位置 if(a[i][j])dl[i][j]=tmp; else{ tmp=j; l[i][j]=0;//細節 } tmp=m+1; for(int j=m;j>0;j--)//計算左邊最近障礙位置 if(a[i][j])dr[i][j]=tmp; else{ tmp=j; r[i][j]=m+1;//細節 } } for(int i=1;i<=m;i++)r[0][i]=m+1;//細節 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]){ h[i][j]=h[i-1][j]+1; l[i][j]=max(l[i-1][j],dl[i][j]);//計算當前矩形最左遇到的障礙 r[i][j]=min(r[i-1][j],dr[i][j]);//計算當前矩形最右遇到的障礙 ans2=max(ans2,h[i][j]*(r[i][j]-l[i][j]-1)); } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&a[i][j]); if((i+j)%2)a[i][j]^=1;//在相應位置染上相反色 } work1(); work2(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]^=1;//重新染色 memset(f,0,sizeof(f)); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(dl,0,sizeof(dl)); memset(dr,0,sizeof(dr)); memset(h,0,sizeof(h)); work1(); work2(); printf("%d\n%d",ans1*ans1,ans2);//最大正方形 最大矩形 return 0; }
牛線Cow Line
康託展開
詳見xly
#include<bits/stdc++.h> using namespace std; #define ll long long int n,m,a[25],b[25]; ll fac[25];//階乘 ll contor(){ ll res=0; for(int i=1;i<=n;i++){ int t=0; for(int j=i+1;j<=n;j++)if(a[j]<a[i])t++; res+=t*1ll*fac[n-i]; } return res; } bool vis[30]; void reverse_contor(ll x){ memset(vis,0,sizeof(vis)); x--; for(int i=1;i<=n;i++){ ll t=x/fac[n-i]; int j; for(j=1;j<=n;j++){ if(!vis[j]){ if(!t)break; t--; } } b[i]=j; vis[j]=1; x%=fac[n-i]; } } int main(){ cin>>n>>m; fac[0]=1; for(int i=1;i<=n;i++)fac[i]=fac[i-1]*1ll*i; while(m--){ char c; cin>>c; if(c=='P'){ ll q; cin>>q;//第K大 reverse_contor(q); for(int i=1;i<=n;i++)printf("%d ",b[i]); printf("\n"); } else{ for(int i=1;i<=n;i++) cin>>a[i]; printf("%lld\n",contor()+1); } } return 0; }
傳紙條
雙路DP
動態規劃
qwq
#include<bits/stdc++.h>
using namespace std;
int n,m,a[55][55];
int f[55][55][55];//一個人的橫縱座標和另一個人的橫座標
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int e=1;e<=i+j-1&&e<=n;e++){
if(i+j-e>m||(e==i&&(i!=n||j!=m)))continue;//!!!
f[i][j][e]=max(max(f[i][j-1][e]/*雙左*/,f[i-1][j][e-1]/*雙上*/),max(f[i][j-1][e-1]/*左+上*/,f[i-1][j][e]/*上+左*/))+a[i][j]+a[e][i+j-e];
}
printf("%d",f[n][m][n]);
return 0;
}
OKR-Periods of Words
KMP
KMP的失配指標思想
?~ ?
#include<bits/stdc++.h>
#define ll long long
using namespace std;
char a[1000010];
int n,fail[1000010];
int main(){
scanf("%d",&n);
scanf("%s",a) ;
int i,j;
ll cnt=0;
fail[0]=fail[1]=0;
j=0;
for(i=1;i<n;i++){//求解next???
while(j&&(a[i]!=a[j]))
j=fail[j];
j+=(a[i]==a[j]);
fail[i+1]=j;
}
for(i=1;i<=n;i++){
j=i;
while(fail[j])
j=fail[j];
if(fail[i]!=0) fail[i]=j;//記憶化
cnt+=i-j;
}
printf("%lld",cnt);
}