20181025小结-2

版权声明:小蒟蒻的博客转载也请注明出处哦 https://blog.csdn.net/qq_42835823/article/details/83421905
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);
}

猜你喜欢

转载自blog.csdn.net/qq_42835823/article/details/83421905