USACO Chapter 5 的几道DP+Chapter 6的rectbarn

USACO Chapter 5 的几道DP+Chapter 6的rectbarn

感觉都是基本的DP,除了charrec不好写罢了。
theme:求出差序列,然后求自身不同的最长公共子串。注意是不同的。
milk4:现ID-DFS枚举方案然后完全背包判定,我常数小直接过了,有TLE可以改记忆化搜索判定。
bigbrn:最大可行正方形,太基础了,连预处理都省了。。。。。
tour:两条线的DP,头脑发热要上SPFA的模板,让后仔细看了数据,三重循环结束。
charrec:很有价值,一般人看着就觉的太难了,然后仔细读完题想想就是DP,但确实不好写。
twofive:感觉最有价值的一道,首先它是一道构造/统计类的DP,然后又是五维DP,各种边界。显然有记忆化搜索比较赚。
最有价值的一题
/**//*
USER:zyn19961
TASK:twofive
LANG:C++
*/

#include
<string>
#include
<cstdio>
#include
<cstring>
#include
<fstream>
#include
<iostream>
#include
<algorithm> 
using namespace std;
//
#define MM(a,i) memset(a,i,sizeof(a))
#define FOR(i,l,r) for (int i=(l);i<=(r);i++)
#define DFOR(i,r,l) for (int i=(r);i>=(l);i--)
//
#define MP make_pair
#define FT first
#define SD second
//
    typedef long long Int64;
    
const int INF=~0U>>2;
    
const int maxn=10;
//
    ifstream fin("twofive.in");
    ofstream fout(
"twofive.out");
    
int F[maxn][maxn][maxn][maxn][maxn];
    
bool used[maxn*maxn];
    
int mx[maxn],my[maxn];
    
int count(int a,int b,int c,int d,int e,int now);
    
void work1();//n
    void work2();//w
//
    int main(){
        
char c;fin>>c;
        
if(c=='N')work1();
        
else work2();
        fin.close();
        fout.close();
        
return 0
        }

    
int count(int a,int b,int c,int d,int e,int now){
        
int &t=F[a][b][c][d][e];
        
if(t)return t;
        
if(used[now])return t=count(a,b,c,d,e,now+1);//
        if(a<5&&mx[0]<now&&my[a]<now)t+=count(a+1,b,c,d,e,now+1);
        
if(b<a&&mx[1]<now&&my[b]<now)t+=count(a,b+1,c,d,e,now+1);
        
if(c<b&&mx[2]<now&&my[c]<now)t+=count(a,b,c+1,d,e,now+1);
        
if(d<c&&mx[3]<now&&my[d]<now)t+=count(a,b,c,d+1,e,now+1);
        
if(e<d&&mx[4]<now&&my[e]<now)t+=count(a,b,c,d,e+1,now+1);
        
return t;
        }

    
void work1(){
        
int sum;fin>>sum;
        
int line[maxn];
        
string s;
        MM(mx,
0xff),MM(my,0xff),MM(used,false),MM(line,0);
        FOR(i,
0,24){
            line[i
/5]++;
            
int j;
            
for(j=0;j<=24;j++)
                
if(!used[j]&&mx[i/5]<j&&my[i%5]<j){
                    used[j]
=true;
                    mx[i
/5]=my[i%5]=j;
                    MM(F,
0);
                    F[
5][5][5][5][5]=1;
                    
int t=count(line[0],line[1],line[2],line[3],line[4],0);
                    
if(sum-t<=0)break;
                    
else sum-=t;
                    used[j]
=false;
                    }

            s
+=char(j+'A');
            }

        fout
<<s<<"\n";
        }

    
void work2(){
        
string s;fin>>s;
        
int sum=0;
        
int line[maxn];
        MM(line,
0),MM(mx,0),MM(my,0),MM(used,false);
        FOR(i,
0,24){
            line[i
/5]++;
            
int j;
            
for(j=0;j<=s[i]-'A'-1;j++)
                
if(!used[j]&&mx[i/5]<j&&my[i%5]<j){
                    mx[i
/5]=my[i%5]=j;
                    MM(F,
0);
                    F[
5][5][5][5][5]=1;
                    used[j]
=true;
                    sum
+=count(line[0],line[1],line[2],line[3],line[4],0);
                    used[j]
=false;
                    }

            used[j]
=true;
            mx[i
/5]=my[i%5]=j;
            }

        fout
<<sum+1<<"\n";
        }

接着看了一下Chapter 6的rectbarn
顾名思义,就是求最大子矩形,显然也是DP。
N久以前看过一篇集训队论文,然后就按照上面的一种方法A掉了这题。
(上面讲了两种方法,我显然写的是最水的N^2的算法)
恶搞了一下代码:
见不得人的代码
/**//*
USER:zyn19961
TASK:rectbarn
LANG:C++
*/

#include
<cstdio>
#include
<cstring>
#include
<fstream>
#include
<iostream>
#include
<algorithm>
using namespace std;
//
#define MM(a,i) memset((a),i,sizeof(a))
#define FOR(i,l,r) for (int i=(l);i<=(r);i++)
#define DFOR(i,r,l) for (int i=(r);i>=(l);i--)
#define NFOR(i,l,r) for (i=(l);i<=(r);i++)
#define NDFOR(i,r,l) for (i=(r);i>=(l);i--)
#define PFOR(p,a,next) for(int p=a;p;p=next[p])
#define NPFOR(p,a,next) for(p=a;p;p=next[p])
//
typedef long long int64;
const int INF=~0U>>2;
const int maxn=3001;
//
ifstream fin("rectbarn.in");
ofstream fout(
"rectbarn.out");
//
bool xx[maxn][maxn];
int F[2][maxn],L[2][maxn],R[2][maxn],Left[maxn],Right[maxn];
int main(){
int r,c,p;
int x,y;
int ans=0,now=0,last=1;
MM(xx,
true);
fin
>>r>>c>>p;
if(!p){fout<<r*c<<"\n";return 0;}
FOR(i,
1,p)fin>>x>>y,xx[y][x]=false;
FOR(i,
1,c){
now
^=1,last^=1;
Left[
0]=0,Right[r+1]=0;
FOR(j,
1,r)xx[i][j]?Left[j]=Left[j-1]+1:Left[j]=0;
DFOR(j,r,
1)xx[i][j]?Right[j]=Right[j+1]+1:Right[j]=0;
FOR(j,
1,r)xx[i][j]? (F[now][j]=F[last][j]+1,
L[now][j]
=min(L[last][j],Left[j]),
R[now][j]
=min(R[last][j],Right[j]))
:(F[now][j]
=0,L[now][j]=INF,R[now][j]=INF);
FOR(j,
1,r)ans=max(ans,F[now][j]*(L[now][j]+R[now][j]-1));
}

fout
<<ans<<"\n";
fin.close();
fout.close();
return 0;
}

你可能感兴趣的:(USACO Chapter 5 的几道DP+Chapter 6的rectbarn)