UESTC 2014 Summer Training #6 Div.2

  又是只过两水题,不过状态有些回升,也是差点一血.

Problem A  SPOJ AMR11A

  显然的dp?就一抖就想到尝试从(R,C)推到(1,1),正着推的话,只能检查某一种解可不可行(就有人想出了二分+DP的神奇方法。。刚卡过。。不过上界是把所有龙加起来。。不闲麻烦的话。。可以按照贪心的方法先跑一个上界,就每一步选当前最优)

  倒着推,龙的话,就加上,药水的话,减去?不够,和1取最大值;某一个点的f[i][j]就是两种策略取最小值;

  f[i][j] = min{ max(1, f[i+1][j]-s[i][j]) ,  max(1, f[i][j+1]-s[i][j] }

  题外话:  自己是12:24提交的这代码。。不过不是scanf,是cin,然后又提交了一个递推的,还是TLE。。。于是就去写水题,写了水题回来写。。。居然会去写搜索。。主要看大家都没怎么过。。以为不是这么简单的dp 0 0 写了好几个小时,想到了求出那个上界的方法,以后搜索优化也许可以用。。不过对这题没什么帮助,后来又去研究卡时。。总之挂很惨。。差一点一血啊

(记忆化)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

const int maxn = 500+10;
const int inf = ~0u >> 2;

int T, r, c, ans;
int f[maxn][maxn], s[maxn][maxn];

int dp(int x, int y)
{    
//    cout << "dp " << x << ' ' << y << endl;
    if(x > r || y > c)    return inf;
    if(f[x][y] != inf)    return f[x][y];
    return    f[x][y] = min(max(dp(x+1, y)-s[x][y], 1), max(dp(x, y+1)-s[x][y], 1));
}

int main()
{
#ifdef LOCAL
    freopen("A.in", "r", stdin);
#endif 
    cin >> T;
    while(T--) {
        cin >> r >> c;
        for(int i = 1; i <= r; i++)
            for(int j = 1; j <= c; j++)
                f[i][j] = inf;
        f[r][c] = 1;
        for(int i = 1; i <= r; i++)
            for(int j = 1; j <= c; j++)
                scanf("%d", s[i]+j);
        cout << dp(1, 1) << endl;
    }
    return 0;
}


Problem B  SPOJ AMR11B

 

  大意是给你圆(圆心+半径)、三角形(三点)、正方形(左下角和边长),球出覆盖的点数,只用考虑整数,包括给的数据

  由于数据很小,我们可以求出其外接?的矩形,枚举点再来判定是否在图形内,需要做判重处理。

  圆用x^2+y^2=R^2这种公式就行了,正方形直接枚举的点就是图形内的(包括边界),主要是三角形比较麻烦,需要用到前几天考察过的计算几何的知识(我都还没写解题报告。。)

  判断三个小三角形面积和是否等于大三角形面积。面积的求法只能暂且记住,好像算是线性代数的知识0 0 都没印象。

  S=|(y3-y1)*(x2-x1)-(y2-y1)*(x3-x1)|/2  (在这道题的情况下,就别/2咯)

  奥,把坐标系移动下,c语言数组不好处理负数呢

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <ctype.h>

using namespace std;

const int maxn = 400;

int T, n, cnt;
bool used[maxn][maxn];

void calcSquare()
{
    int x, y, l;
    scanf("%d%d%d", &x, &y, &l);
    x += 100;    y += 100;
    for(int i = 0; i <= l; i++)
        for(int j = 0; j <= l; j++)
            if(!used[x+i][y+j]) {
                used[x+i][y+j] = 1;
                cnt++;
            }
} 

void calcCircle()
{
    int x0, y0, r;
    scanf("%d%d%d", &x0, &y0, &r);
    x0 += 100;    y0 += 100;
    int x = x0-r, y = y0-r, l = 2*r;
    for(int i = 0; i <= l; i++)
        for(int j = 0; j <= l; j++) {
//            if(i == 1 && j == 2)    cout << ( !used[x+i][y+i] && (x+i-x0)*(x+i-x0)+(y+j-y0)*(y+j-y0) <= r*r ) << endl;

//                int a = (x+i-x0)*(x+i-x0)+(y+j-y0)*(y+j-y0), b = r*r;
//                cout << x+i << ' ' << y+j << ' ' << a << ' ' << b << endl;
            if(!used[x+i][y+j] && (x+i-x0)*(x+i-x0)+(y+j-y0)*(y+j-y0) <= r*r) {
//                if( (x+i-x0)*(x+i-x0)+(y+j-y0)*(y+j-y0) > r*r)
                //if(a > b)    continue;
//                cout << "COUNT" << endl;
//                cout << "Change " << x+i << ' ' << y+j << endl;
                used[x+i][y+j] = 1;
//                cout << "Change " << x+i << ' ' << y+j << endl;
                cnt++;
            }
        }
}

int area(int x1, int y1, int x2, int y2, int x3, int y3)
{
    //notice real area is this one divide 2
    return abs((y3-y1)*(x2-x1)-(y2-y1)*(x3-x1));
}

void calcTriangle()
{ 
    int x1, x2, x3, y1, y2, y3;
    scanf("%d%d%d%d%d%d", &x1, &y1, &x2, &y2, &x3, &y3);
    x1 += 100;    y1 += 100;    x2 += 100;    y2 += 100;    x3 += 100;    y3 += 100;
    int a, b, c, d;
    a = min(x1, min(x2, x3));    b = min(y1, min(y2, y3));
    c = max(x1, max(x2, x3));    d = max(y1, max(y2, y3));
    for(int i = a; i <= c; i++)
        for(int j = b; j <= d; j++)
            if(!used[i][j]) {
                if(area(i, j, x1, y1, x2, y2) + area(i, j, x2, y2, x3, y3) + area(i, j, x1, y1, x3, y3) != area(x1, y1, x2, y2, x3, y3))
                    continue;
                used[i][j] = 1;
                cnt++;
            }
}

int main()
{
#ifdef LOCAL
    freopen("B.in", "r", stdin);
#endif 
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        cnt = 0;
        memset(used, 0, sizeof(used));
        while(n--) {
            char c;
            while(!isalpha(c = getchar())) ; 
            switch(c) {
                case 'C':    calcCircle();    break;
                case 'T':    calcTriangle();    break;
                case 'S':    calcSquare();    break;
                default:    break;
            }
        }
        printf("%d
", cnt);
    }
    return 0;
}

Problem E  SPOJ AMR11E

  找出第n个幸运数(因子中至少能找出3个不同的质数) 

  由于n比较小,我直接打表出1000个幸运数。。。打表写得比较渣。一开始还写错了。代码不贴咯。

Problem G  SPOJ AMR11G

  就水题。。。判断下有没D  vjudge爬虫代码估计渣了,Sample Input格式有点问题,害得我代码调了很久

//  cin.getline(str, [length], [endcharacter])(会读入endcharacter)

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 100;

int T, N;
char c;

int main()
{
#ifdef LOCAL
    freopen("G.in" , "r", stdin);
#endif
    cin >> T;
    cin.ignore();
    while(T--) {
         {
            char s[maxn];
            cin.getline(s, maxn);
//            cout << s << endl;
//            cin.ignore();
            bool ok = true;        
            for(unsigned int i = 0; i < strlen(s); i++)
                if(s[i] == 'D') {
                    ok = false;
                    break;
                }
            if(!ok)    cout << "You shall not pass!" << endl;
            else    cout << "Possible" << endl;
        }
    }
    return 0;
}

Problem J  SPOJ AMR11J

  比较裸的bfs,数据量不大,不用担心什么,关键是策略写对没。

  主要问题在于两个部落同时expand到一点时,会冲突,标记为'*',而bfs是有先后的,除非多线程?

  所以需要延时处理,记录要更新的地点,记录下要更新 为 的标记:另开一个数组,先到先标记,后到发现已标记就置为'*’

  !!!!这里思路就又错了,逻辑不紧哎。  发现标记不同才置为'*'

  否则会出现b.b  ->  b*b

  

(可能是vector降低了效率,跑得比较慢)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
#include<utility>
#include<cstring>

using namespace std;

const int maxn = 500+10;
const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, 1, -1};

typedef pair<int, int> pii;

int T, R, C;
char m[maxn][maxn], ocp[maxn][maxn];
vector<pii>    v;
queue<pii> q;

void update()
{
    for(int i = 0, t = v.size(); i < t; i++) {
        int x = v[i].first, y = v[i].second;
        if(m[x][y] == '.') {
            m[x][y] = ocp[x][y]; 
            q.push(make_pair(x, y));
        }
    }
    v.clear();
}

bool can_move(int x, int y)
{
    return x >= 1 && x <= R && y >= 1 && y <= C && m[x][y] == '.';
}

void bfs()
{
    for(int i = 1; i <= R; i++)
        for(int j = 1; j <= C; j++)
            if(m[i][j] <= 'z' && m[i][j] >= 'a')
                q.push(make_pair(i, j));
    while(!q.empty()) {
        pii tmp = q.front();    q.pop();
        int x = tmp.first, y = tmp.second;
        for(int i = 0; i < 4; i++) {
            int nx = x+dx[i], ny = y+dy[i];
            if(can_move(nx, ny)) {
                if(ocp[nx][ny] && ocp[nx][ny] != m[x][y])
                    m[nx][ny] = '*';            
                else {
                    v.push_back(make_pair(nx, ny));
                    ocp[nx][ny] = m[x][y];
                }
            }
        }
        if(q.empty())    update();
    }
}

int main()
{
#ifdef LOCAL
    freopen("J.in", "r", stdin);
#endif
    cin >> T;
    while(T--) {
        cin >> R >> C;
        while(!q.empty())    q.pop();
        v.clear();
        memset(ocp, 0, sizeof(ocp));
        for(int i = 1; i <= R; i++)
                cin >> (m[i]+1);
        bfs();
        for(int i = 1; i <= R; i++)
            cout << (m[i]+1) << endl;
    }
    return 0;
}


  A题瞄一眼思路就来了,所以直接写的A,无奈犯傻逼,数据量高达500*500=250000 25W啊 TLE得没办法

  然后去跟榜做E、G,E题打表因为自己没读透题,浪费很多时间,这一来一去心态乱了很多。总感觉自己能写A,再去搞没办法又搜索又减枝,反正搞到快4点也一直TLE

  心态真的崩了,一开始以为能做的题,结果卡了这么久,我交了43发。。。彻底蒙了。还有一丝理智,去看J,又慌了!根本不用考虑time的,还去傻逼写优先队来保证每次出队是time最小的,其实就是跟新完一圈又跟新下一圈。不过无伤大雅,有个小错误没时间去发现了。2题GG。rank又垫底。

  心态这玩意,真的不是一两天能改好的,也要看比赛的重要性,多加控制吧。

  自己读题问题也很大的,时常没考虑好就去写。写完样例一跑就傻逼。

  策略:

  问题在于有灵感想出大概思路的时候,不要抢着去写,再读题,再跑样例,理清思路再写代码,最后思考极限数据(也可以一开始就有考虑)

  其实这种策略不是一次想提出,关键是自己执行力度,容易忘掉。

  经常总结才行!

原文地址:https://www.cnblogs.com/gemmeg/p/3857267.html