【解题报告】 SRM412_div1_250pt 和 SRM411_div2_900pt

来源:互联网 发布:切削参数计算软件 编辑:程序博客网 时间:2024/05/21 16:11

SRM412_div1_250: Forbidden String

题目链接请点击这里。

题目描述:只考虑由A,B,C三字母组成的字符串,若字符串S存在三个连续的字母使得其中一个为A,一个为B,一个为C,则称S为forbidden string。例如,BAACAACCBAAA 是Forbidden String,而AABBCCAABB 不是。

给你字符串长度n,要求你计算有多少个not forbidden字符串。1<=n<=30。

解析1:可模拟字符串从长度为0开始不断往后append字母至长度为n的过程。当前位可添加的字母仅由其前2位决定(如果长度>=2的话,若长度<2可自由添加),而其前2位可能的情况有以下几种:AA,BB,CC,AB,AC,BC,BA,CA,CB

分别用1,2,3表示A,B,C的话,则可以用不大于40的几个数来表示所有可能的前缀。另外n的范围较小,因此首先想到用dp解决。dp[a][b]表示前a位的末2位对应整数为b时的非forbidden string数量(b=11,22,33,12,13,23,21,31,32)。则根据b的情况进行讨论,进行状态转换。当b对应的前缀其2位均相同时,则可添加A,B,C三种。当b对应的前缀其2位不同时,则可添加2种,具体哪2种由b决定。例如b=BA时,可添加A,B两种,不能添加C。

解析2:在解析1的基础上,我们知道最终not forbidden的字符串只由两类字符串组成:末2位相同和末2位不同的字符串,用r[t]表示长度为t且末2位相同的非forbidden字符串。用n[t]表示末2位不相同的非forbidden字符串。则r[t], n[t]与r[t-1], n[t-1]之间存在什么样的关系?由解析1可很容易地推出:

r[t] = r[t-1]+n[t-1];

n[t]=r[t-1]*2+n[t-1];

由此可在O(n)时间内解决。

 

typedef long long ll;

long long ForbiddenStrings::countNotForbidden(int N) {
    if(N == 1) return 3;
    if(N == 2) return 9;
     ll r[100], n[100];
//r:the forbidden string that the last 2 chars are same. n:the forbidden string that the last 2 are diff.

     r[2]=3;n[2]=6;
    for(int i = 3; i <= N; i++){
         r[i] = r[i-1]+n[i-1];
         n[i] = n[i-1]+r[i-1]*2;
    }
    return r[N]+n[N];
}

SRM411_div2_900: HoleCakeCuts

题目链接请点击这里。

题目描述:有一个正方形蛋糕,其中心点坐标为(0,0),X轴正向向右,Y轴正向向上,均与正方形边长平行。蛋糕边长为2O。在其内挖走一块边长为2I的同心正方形(即中心点也在(0,0))。然后对这个特殊的蛋糕进行横向(与Y轴平行)或纵向(与X轴平行)的切割。切割坐标已知(即横向切割的Y坐标和纵向切割的X坐标)。每个切割的长度均是无限的。求切割之后还剩多少块蛋糕(面积>0)。

题目解析:先不管蛋糕内的空心洞。用(x1,y1,x2,y2)表示一块矩形区域,其中x1,y1为左上角坐标,x2,y2为右下角坐标。每次切割都将当前矩形分为两部分,横向切割分为上下,纵向切割分为左右,根据切割坐标可得到两部分的左上角和右下角的坐标,由此进行递归。

关键问题在于,由于存在空心洞,因此需要注意两种情况:

srm411_holecakecuts_case_2_1.jpgsrm411_holecakecuts_case_2_2.jpg

即当某个切使得其得到的子矩形中有被空洞一分为二的情况时,此时这个子矩形不是一个完整的矩形(只剩下头和尾两部分,见图中黄色区域,中间都是空的),此时必须分将此子矩形为上下或左右两个子部分(中间的为空不包括在内),然后继续切割。根据空洞的边长可得到其左右或上下两个子块的坐标。代码如下:

 

class HoleCakeCuts {
public:
    int cutTheCake(int, int, vector <int>, vector <int>);
};

int out,in;
vector<pair<int,char> > cut;

bool In(int x1,int y1,int x2,int y2){
    if(abs(x1)<=in && abs(x2)<=in && abs(y1)<=in && abs(y2)<=in) return true;
    return false;
}

int solve(int x1,int y1,int x2,int y2,int p1){
    if(In(x1,y1,x2,y2)) return 0;
//if current area is totally included by In, that means this area is empty.

    if(x1==x2 || y1==y2) return 0;
//area should >0

    if(p1 == cut.size()){
        if(x1>=-in && x2<=in && y1>=in && y2<=-in) return 2;
//key point! If current area is seprated by In into 2 parts.

        if(y1<=in && y2>=-in && x1<=-in && x2>=in) return 2;
//key point! Then this area should count as 2 areas.

        return 1;
    }
    if(x1>=-in && x2<=in && y1>=in && y2<=-in){
//key point! If area is sperated by In into 2parts.

        return solve(x1,y1,x2,in,p1)+solve(x1,-in,x2,y2,p1);
    }
    else if(y1<=in && y2>=-in && x1<=-in && x2>=in){
//Then we should seperate it into 2parts, ans handle individually.

        return solve(x1,y1,-in,y2,p1)+solve(in,y1,x2,y2,p1);
    }
    bool ish=false,isv=false;
    int i;
    for(i = p1; i < cut.size(); i++){
        if(cut[i].second == 'h'){
            if(cut[i].first <= y1 && cut[i].first >=y2){
//valid cut for current area.

                 ish = true;
                break;
            }
        }
        else{
            if(cut[i].first >= x1 && cut[i].first <=x2){
//valid cut for current area.

                 isv = true;
                break;
            }
        }
    }
    if(!ish && !isv) return solve(x1,y1,x2,y2,p1+1);
//this cut is invalid for current area. Then just move on.

    if(ish){
//horizonal cut

        return solve(x1,y1,x2,cut[i].first,p1+1)+solve(x1,cut[i].first,x2,y2,p1+1);
    }
    else{
//vertical cut

        return solve(x1,y1,cut[i].first,y2,p1+1)+solve(cut[i].first,y1,x2,y2,p1+1);
    }
}

int HoleCakeCuts::cutTheCake(int cakeLength, int holeLength, vector <int> h, vector <int> v) {
     out=cakeLength;
     in=holeLength;
     cut.clear();
    for(int i = 0; i < h.size(); i++)
         cut.push_back(make_pair(h[i],'h'));
    for(int i = 0; i < v.size(); i++)
         cut.push_back(make_pair(v[i],'v'));
    return solve(-out,out,out,-out,0);
//topleftx,toplefty,downrightx,downrighty

}

 

 

原创粉丝点击