【xdoj新手教学】WEEKLY MISSION 2

实话实说,这次的难度要高很多,很多题目都是比赛的原题,虽然很多方法是和上次类似的,但可以说已经进阶了不少。不知道照这样下去,后面的题目会不会已经变成暑训的难度。。。

一道一道说一说吧

A
小模拟,只要按照题目要求就可以了,没有什么思维。

贴代码

# include <stdio.h>

const int MAX_N = 20;

int dx[4] = {1 , 0 , -1 , 0}, dy[4] = {0 , 1 , 0 , -1};
int f[MAX_N + 1][MAX_N + 1];
int N, M;

int main()
{
    while(~scanf("%d %d", &N, &M))
    {
        if(M == 0 && N == 0)
            break;

        int i, j, k;
        for(i = 0 ; i < N ; i++)
            for(j = 0 ; j < M ; j++)
                scanf("%d", &f[i][j]);

        int d = -500, dh, dl;
        for(i = 0 ; i < N ; i++)
        {
            for(j = 0; j < M ; j++)
            {
                int ps = (f[i][j] < 0) * 2 - 1 , sum = 0;
                for(k = 0 ; k < 4 ; k++)
                {
                    int nx = i + dx[k], ny = j + dy[k];
                    if(nx >= 0 && nx < N && ny >= 0 && ny < M)
                        sum += ps * f[nx][ny];
                }

                if(sum > d)
                {
                    d = sum;
                    dh = i;
                    dl = j;
                }
            }
        }
        printf("%d %d %d\n", dh + 1, dl + 1, d);
    }

    return 0;
}

B
题目要求找出最大的一组连续数列,保证所有元素都不相同。一道变形的尺取法,只需要用一个set来存储连续数列的所有的不同元素即可。

贴代码

# include <stdio.h>
# include <set>
# include <algorithm>

using namespace std;

const int MAX_N = 1e6;

int A[MAX_N];
int T, N;

int main()
{
    scanf("%d", &T);

    while(T--)
    {
        scanf("%d", &N);

        int i;
        for(i = 0 ; i < N ; i++)
            scanf("%d", &A[i]);

        int fro = 0, bak = 0, ans = 1;
        set<int> s;
        s.insert(A[0]);

        for(i = 1 ; i < N ; i++)
        {
            if(s.find(A[i]) != s.end())
            {
                while(A[bak] != A[i])
                    s.erase(A[bak++]);

                bak++;
                fro++;
            }
            else
            {
                s.insert(A[i]);
                fro++;
                ans = max(fro - bak + 1 , ans);
            }
        }

        printf("%d\n", ans);
    }

    return 0;
} 

C
要求找到点集中所有的正方形,正好之前的训练赛做到一道类似的题目,只需要查询所有的点对,看看能不能组成一个正方形的对角点,然后把结果除二即可(因为每个正方形有两组对点),至于如何查找点对,这是一个数学问题,不是程序问题,这里就不多说了。

贴代码

# include <stdio.h>
# include <algorithm>
# include <set>

using namespace std;

typedef pair<int , int> P;

const int MAX_N = 1000;

set<P> s;
P pos[MAX_N];
int N;

inline int ab(int a)
{
    return (a < 0) ? -a : a;
}

bool fin(P a , P b)
{
    int dx = b.first - a.first, dy = b.second - a.second;

    if((dx & 1) != (dy & 1))
        return false;

    int ia = (dx + dy) / 2, ib = (dy - dx) / 2;

    return s.find(P(a.first + ia , a.second + ib)) != s.end() && s.find(P(b.first - ia , b.second - ib)) != s.end();
} 

int main()
{
    while(1)
    {
        scanf("%d", &N);

        if(!N)
            break;

        s.clear();

        int i, j;
        for(i = 0 ; i < N ; i++)
        {
            scanf("%d %d", &pos[i].first, &pos[i].second);
            s.insert(pos[i]);
        }

        int ans = 0;
        for(i = 0 ; i < N ; i++)
        {
            for(j = i + 1 ; j < N ; j++)
            {
                if(fin(pos[i] , pos[j]))
                {
                    ans++;
                }
            }
        }
        printf("%d\n", ans / 2);
    }

    return 0;
}

D
有点坑的一道题,反正瞎搞了一阵就搞好了,之前看别人说是贪心,于是就尝试了一下,每次的lr都尽量把这个数组往b上凑,于是就成功了。至于怎么凑,只要把他们的每一个元素标记为b中的位置,再进行一个排序即可。

# include <stdio.h>
# include <algorithm>

using namespace std;

const int MAX_N = 1000;

int A[MAX_N];
int C[MAX_N];
int T, N, M;

int main()
{
    scanf("%d", &T);

    while(T--)
    {
        scanf("%d %d", &N, &M);

        fill(C , C + N , -1);

        int i, j;
        for(i = 0 ; i < N ; i++)
            scanf("%d", &A[i]);

        int s;
        for(i = 0 ; i < N ; i++)
        {
            scanf("%d", &s);

            for(j = 0 ; j < N ; j++)
                if(A[j] == s && C[j] == -1)
                {
                    C[j] = i;
                    break;
                }
        }

        int l, r;
        for(i = 0 ; i < M ; i++)
        {
            scanf("%d %d", &l, &r);
            sort(C + l - 1 , C + r);
        }

        for(i = 0 ; i < N ; i++)
        {
            if(C[i] != i)
            {
                puts("No");
                break;
            } 
        }

        if(i == N)
            puts("Yes");
    }

    return 0;
} 

E
一道思维题,保证只能余一半一下,因为若可以余一半以上,那么那个模的数字必然小于余数,这是不成立的,并且所有余0至一半的都可以发现就是N-i类型的,于是成立。

贴代码

# include <stdio.h>

int main()
{
    int N;
    scanf("%d", &N);

    while(N--)
    {
        int a;
        scanf("%d", &a);

        printf("%d\n", (a + 3) / 2);
    }

    return 0;
}

F
这道题非常麻烦,主要思想在于凑(L + 1),因为可以发现最密集的步数应该是每(L + 1)两步,所以凑一凑即可,这道题细节问题比较多,比如和之前的那个点还有后面的第二个点都要考虑,反正觉得是有点问题的。

贴代码

# include <stdio.h>
# include <algorithm>

using namespace std;

const int MAX_N = 2 * 1e5;

int A[MAX_N + 2];
int T, N, M, L;

int main()
{
    scanf("%d", &T);
    int tt = 0;
    while(T--)
    {
        scanf("%d %d %d", &N, &M, &L);

        int i;
        for(i = 1 ; i <= N ; i++)
            scanf("%d", &A[i]);

        A[0] = 0;
        A[N + 1] = M;
        sort(A + 1 , A + N + 1);

        int step = 0;
        int k = L;
        for(i = 0 ; i <= N ; i++)
        {
            int x = (A[i + 1] - A[i]) % (L + 1);
            int y = (A[i + 1] - A[i]) / (L + 1);
            if(k + x > L)
            {
                step += 2 * y + 1;
                k = x;
            }
            else
            {
                step += 2 * y;
                k += x;
            }

        }

        printf("Case #%d: %d\n", ++tt, step);

    }

    return 0;
} 

G
一道水题,直接写即可

贴代码

# include <stdio.h>

char a[2][20];

int main()
{
    while(~scanf("%s %s", a[0], a[1]))
    {
        int n[2], j;
        int i;
        for(i = 0 ; i < 2 ; i++)
        {
            n[i] = 0;
            for(j = 0 ; a[i][j] ; j++)
            {
                if(a[i][j] > 57 || a[i][j] < 48)
                    continue;

                n[i] *= 10;
                n[i] += a[i][j] - 48;
            }

            if(a[i][0] == '-')
                n[i] *= -1;
        }

        printf("%d\n", n[0] + n[1]);
    }

    return 0;
} 

H
首先要找一个平方数,还要保证这个数字没有超过2次的质因子,并且与x的绝对值最小,想了半天想不出什么好办法,就用了一个暴力查找,结果15ms过没说明这道题数据还是挺水的,思路是先找出不小于给出数的一个平方数(二分查找即可),然后往前后一个一个查找,每个数试一试是否成立,试到成立为止,然后再把前和后中较小的那个输出即可。

贴代码

# include <stdio.h>
# include <algorithm>

using namespace std;

typedef long long ll;

int T;
ll X;

ll ab(ll a)
{
    return (a < 0) ? -a : a;
}

ll fin(ll x)
{
    ll lb = 0, ub = min(x , (ll)1e9);
    while(ub - lb > 1)
    {
        ll mid = (ub + lb) / 2;

        if(mid * mid >= x)
            ub = mid;
        else
            lb = mid;
    }

    return ub;
}

bool ok(ll k)
{
    ll i;
    for(i = 2 ; i * i <= k ; i++)
    {
        if(k % (i * i) == 0)
            return false;

        if(k % i == 0)
            k /= i;
    }

    return true;
}

int main()
{
    scanf("%d", &T);

    while(T--)
    {
        scanf("%lld", &X);

        if(X < 4)
        {
            printf("%d\n", 4 - X);
            continue;
        }

        ll ans;
        ll n = fin(X);

        int i = 0;
        while(1)
        {
            if(ok(n + i))
            {
                ans = (n + i) * (n + i) - X;
                break;
            }
            i++;
        }

        i = 1;
        while(1)
        {
            if(ok(n - i))
            {
                ans =  min(ans , X - (n - i) * (n - i));
                break;
            }
            i++;
        }
        printf("%lld\n", ans);
    }

    return 0;
} 

I
给出一组数,再给出一个范围问你这里面的数字有几个,没有任何对数组的操作,是一道简单的二分题,用一下二分函数即可。(另外建议记住精确这两个函数的作用和用法)

贴代码

# include <stdio.h>
# include <algorithm>

using namespace std;

const int MAX_N = 1e5;

int A[MAX_N];
int N, M, T;

int main()
{
    int tt = 0;
    scanf("%d", &T);

    while(T--)
    {
        scanf("%d %d", &N, &M);

        int i;
        for(i = 0 ; i < N ; i++)
            scanf("%d", &A[i]);

        sort(A , A + N);

        printf("Case %d:\n", ++tt);
        int x, y;
        for(i = 0 ; i < M ; i++)
        {
            scanf("%d %d", &x, &y);
            printf("%d\n", upper_bound(A , A + N , y) - lower_bound(A , A + N , x));
        }
    }

    return 0;
}

J
一道经典的贪心题(换汤不换药的题目做过n次了), 直接按照结束时间贪心地一个一个查找即可。

贴代码

# include <stdio.h>
# include <algorithm>

using namespace std;

typedef pair<int , int> P;

const int MAX_N = 100;

P tv[MAX_N];
int N;

int main()
{   
    while(~scanf("%d", &N))
    {
        if(!N)
            break;

        int i;
        for(i = 0 ; i < N ; i++)
            scanf("%d %d", &tv[i].second, &tv[i].first);

        sort(tv , tv + N);

        int t = 0, sum = 0;

        i = 0;
        while(i < N)
        {
            if(tv[i].second >= t)
            {
                sum++;
                t = tv[i].first;
            }
            i++;
        }

        printf("%d\n", sum);
    }

    return 0;
}

K
一道大模拟,不过在经历过无数大模拟之后,我倒感觉还行,只要根据题目要求一点一点来即可,我建议能够模块化的东西一定要模块化,这种题写的越简洁越不容易出错,反正很多技巧不是一蹴而就的,需要大量的练习。这次的题目其实说的挺清晰的了,所以也没有遇到什么阻力就过了,甚至比做前面的题感觉还好 。

贴代码

# include <stdio.h>
# include <string.h>

const int MAX_N = 1e3 + 7;

int sx[3][4][4] = {{{0 , 0 , 1 , 1} , {0 , 0 , 0 , 0} , {0 , 0 , 0 , 0} , {0 , 0 , 0 , 0}} , {{0 , 0 , 0 , 0} , {0 , 1 , 2 , 3} , {0 , 0 , 0 , 0} , {0 , 0 , 0 , 0}} , {{0 , 0 , 1 , 2} , {0 , 0 , 0 , 1} , {0 , 1 , 2 , 2} , {0 , 1 , 1 , 1}}}, sy[3][4][4] = {{{0 , 1 , 0 , 1} , {0 , 0 , 0 , 0} , {0 , 0 , 0 , 0} , {0 , 0 , 0 , 0}} , {{0 , 1 , 2 , 3} , {0 , 0 , 0 , 0} , {0 , 0 , 0 , 0} , {0 , 0 , 0 , 0}} , {{0 , 1 , 0 , 0} , {0 , 1 , 2 , 2} , {1 , 1 , 0 , 1} , {0 , 0 , 1 , 2}}};

bool box[10][15];

int A[MAX_N];
char s[MAX_N];
int ans;
int T, N;
int tt;

bool chek(int x , int y , int z , int sp)
{
    int i;
    for(i = 0 ; i < 4 ; i++)
    {
        int nx = x + sx[sp][z][i], ny = y + sy[sp][z][i];
        if(nx < 0 || nx >= 9 || ny < 0 || box[nx][ny])
            return false;
    }

    return true;
}

bool sea(int n)
{
    int i, j;
    for(i = 0 ; i < 9 ; i++)
    {
        if(!box[i][n])
            return false;
    }

    ans++;
    for(i = 0 ; i < 9 ; i++)
    {
        for(j = n ; j < 11 ; j++)
        {
            box[i][j] = box[i][j + 1];
        }
        box[i][11] = 0;
    }
    return true;
}

void solve()
{
    ans = 0;
    memset(box , 0 , sizeof(box));
    int tim = 0;

    int shp, xu, px, py;

    int i, j;
    for(i = 0 ; i < N ; i++)
    {
        px = 3;
        py = 8;
        shp = A[i];
        xu = 0;

        while(1)
        {       
            if(s[tim])
            {
                char c = s[tim++];

                int cx = px, cy = py, cxu = xu;
                if(c == 'a')
                    cx--;
                else if(c == 'd')
                    cx++;
                else if(c == 's')
                    cy--;
                else if(c == 'w')
                { 
                    if(shp != 0)
                        cxu++;

                    if(cxu == 2 && shp == 1)
                        cxu = 0;
                    if(cxu == 4 && shp == 2)
                        cxu = 0; 
                } 

                if(chek(cx , cy , cxu , shp))
                {
                    px = cx;
                    py = cy;
                    xu = cxu;
                }
            }

            if(!chek(px , py - 1 , xu , shp))
            {
                for(j = 0 ; j < 4 ; j++)
                    box[px + sx[shp][xu][j]][py + sy[shp][xu][j]] = 1;

                for(j = 0 ; j < 12 ; j++)
                    while(sea(j));
            /*
            int u, v;
            for(u = 11 ; u >= 0 ; u--)
            {
                for(v = 0 ; v < 9 ; v++)
                {
                    printf("%d ", box[v][u]);
                }puts("");
            }
            puts("");
            */  
                break;
            }
            py--;
        }
    }

    printf("Case %d: %d\n", tt++, ans);
}

int main()
{
    scanf("%d", &T);

    tt = 1;
    while(T--)
    {   
        scanf("%d", &N);

        scanf("%s", s);
        int i;
        for(i = 0 ; i < N ; i++)
            scanf("%d", &A[i]);

        solve();
    }

    return 0;
}

L
好像在xdoj见过换汤不换药的题目,虽然我们不能快速正面计算出结果,但是如果给出一个预算,我们可以用n的复杂度验证是否成立,只要一个一个贪心地推即可,而且可以保证成立于不成立是单调的,所以直接用二分找出那个分界即可。

贴代码

# include <stdio.h>

const int MAX_N = 1e5;

int A[MAX_N];
int N, M;

bool ok(int n)
{
    int sum = 1, res = n;

    int i = 0;
    while(i < N)
    {
        if(n < A[i])
            return false;

        if(res < A[i])
        {
            sum++;
            res = n - A[i];
        }
        else
            res -= A[i];

        i++;
    }

    return sum <= M;
}

int main()
{
    while(~scanf("%d %d", &N, &M))
    {
        int i;
        for(i = 0 ; i < N ; i++)
            scanf("%d", &A[i]);

        int lb = 0, ub = 1e9;

        while(ub - lb > 1)
        {
            int mid = (lb + ub) / 2;

            if(ok(mid))
                ub = mid;
            else
                lb = mid;
        }
        printf("%d\n", ub);
    } 

    return 0;
} 

M
思维题,因为可以任选a和b的和差所以可以发现一至N里面的元素有且只有被a和b的最大公约数整除的元素可以被选,而且不管怎么选最后都是能够选到全体的,所以只需要判断这些数的奇偶即可

贴代码

# include <stdio.h>

int N, T;
int A, B;

int gcd(int a , int b)
{
    if(!b)
        return a;

    return gcd(b , a % b);
}

int main()
{
    scanf("%d", &T);

    int tt = 0;
    while(T--)
    {
        scanf("%d %d %d", &N, &A, &B);

        printf("Case #%d: ", ++tt);
        if((N / gcd(A , B)) % 2 == 0)
            puts("Iaka");
        else
            puts("Yuwgna");
    }

    return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_40772738/article/details/80335550