The 12th Zhejiang Provincial Collegiate Contest(2015浙江省省赛)

第一次类似组队那样练题,做到后期感觉自己还是后劲不足,难题还是做不来。

下午做出了6道题目,ALGHJB,可能水题比较多,合胃口,但是加深难度之后,还是力不从心,想拿铜还是要苦练。

等题加入题库了再加链接。


A题:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3869

大水题,sb的是我开场wa了一发 。,。

因为数据实在小,所以搞了一个大暴力,然后<=的=号手滑加了上去。。。

深表遗憾。。。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 1000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = 4 * atan(1.0);
const double ee = exp(1.0);

int n;
int a[maxn];

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        memset(a, 0, sizeof(a));
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {
            int x;
            scanf("%d", &x);
            a[x]++;
        }
        int posans = -1;
        int maxval = 0;
        bool flag = true;
        for (int i = 1; i < maxn; i++)
        {
            if (maxval < a[i])
            {
                maxval = a[i];
                posans = i;
            }
        }
        for (int i = 1; i < maxn; i++)
        {
            if (maxval == a[i] && posans != i)
            {
                flag = false;
                break;
            }
        }
        if (flag)
        {
            printf("%d\n", posans);
        }
        else
        {
            printf("Nobody\n");
        }
    }
    return 0;
}

L:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3880

学弟A的,听说是个大水题。

。,。

代码:

#include <cstdio>
int main()
{
    int n,i,j,k,t,x;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        k=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(x>6000)k++;
        }
        printf("%d\n",k);
    }
    return 0;
}
果然


G:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3875

题目看懂就好做了,大模拟。

排个序,找到三种菜的价格中位数,累和输出。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = 4 * atan(1.0);
const double ee = exp(1.0);

struct C
{
    string name;
    int price;
} ss[maxn], mm[maxn], dd[maxn];

bool cmp(C a, C b)
{
    if (a.price == b.price)
        return a.name < b.name;
    return a.price < b.price;
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int s, m, d;
        scanf("%d%d%d", &s, &m, &d);
        for (int i = 0; i < s; i++)
        {
            cin >> ss[i].name >> ss[i].price;
        }
        for (int i = 0; i < m; i++)
        {
            cin >> mm[i].name >> mm[i].price;
        }
        for (int i = 0; i < d; i++)
        {
            cin >> dd[i].name >> dd[i].price;
        }
        sort(ss, ss + s, cmp);
        sort(mm, mm + m, cmp);
        sort(dd, dd + d, cmp);
        int poss = s / 2;
        int posm = m / 2;
        int posd = d / 2;
        printf("%d ", ss[poss].price + mm[posm].price + dd[posd].price);
        cout << ss[poss].name << " "  << mm[posm].name << " " << dd[posd].name << endl;
    }
    return 0;
}

H:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3876

重要的点就是找到某年的5月1号是星期几。

用了一个算某天是星期几的算法。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = 4 * atan(1.0);
const double ee = exp(1.0);

int whatday(int d, int m, int y)
{
    int ans;
    if (m == 1 || m == 2)
    {
        m += 12;
        y--;
    }
    if ((y < 1752) || (y == 1752 && m < 9) || (y == 1752 && m == 9 && d < 3))
        ans = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 + 5) % 7;
    else
        ans = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
    return ans + 1;
}

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int year;
        scanf("%d", &year);
        int t = whatday(1, 5, year);
        int ans;
        if (t == 1)
            ans = 9;
        if (t == 2)
            ans = 6;
        if (t == 3)
            ans = 5;
        if (t == 4)
            ans = 5;
        if (t == 5)
            ans = 5;
        if (t == 6)
            ans = 5;
        if (t == 7)
            ans = 6;
        cout << ans << endl;
    }
    return 0;
}

J:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3878

- - 这题,我用了一个笨方法,把转换图搞出来,然后map一一对应。

还有一个点,就是判断map键值是否存在那个函数的用法。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long

using namespace std;
const int maxn = 1000000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = 4 * atan(1.0);
const double ee = exp(1.0);

map<char, char> key;

void init()
{
    key['-'] = '[';
    key['_'] = '{';
    key['='] = ']';
    key['+'] = '}';

    key['Q'] = '"';
    key['q'] = '\'';
    key['W'] = '<';
    key['w'] = ',';
    key['E'] = '>';
    key['e'] = '.';

    key['R'] = 'P';
    key['r'] = 'p';
    key['T'] = 'Y';
    key['t'] = 'y';
    key['Y'] = 'F';
    key['y'] = 'f';
    key['U'] = 'G';
    key['u'] = 'g';
    key['I'] = 'C';
    key['i'] = 'c';
    key['O'] = 'R';
    key['o'] = 'r';
    key['P'] = 'L';
    key['p'] = 'l';
    key['{'] = '?';
    key['['] = '/';
    key['}'] = '+';
    key[']'] = '=';

    key['S'] = 'O';
    key['s'] = 'o';
    key['D'] = 'E';
    key['d'] = 'e';
    key['F'] = 'U';
    key['f'] = 'u';
    key['G'] = 'I';
    key['g'] = 'i';
    key['H'] = 'D';
    key['h'] = 'd';
    key['J'] = 'H';
    key['j'] = 'h';
    key['K'] = 'T';
    key['k'] = 't';
    key['L'] = 'N';
    key['l'] = 'n';
    key[':'] = 'S';
    key[';'] = 's';
    key['"'] = '_';
    key['\''] = '-';

    key['Z'] = ':';
    key['X'] = 'Q';
    key['C'] = 'J';
    key['V'] = 'K';
    key['B'] = 'X';
    key['N'] = 'B';
    key['<'] = 'W';
    key['>'] = 'V';
    key['?'] = 'Z';

    key['z'] = ';';
    key['x'] = 'q';
    key['c'] = 'j';
    key['v'] = 'k';
    key['b'] = 'x';
    key['n'] = 'b';
    key[','] = 'w';
    key['.'] = 'v';
    key['/'] = 'z';
}

bool isExist(const char& keyName)
{
    return ( key.find(keyName) != key.end() );
}

char str[maxn];
char ans[maxn];

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    init();
    while (gets(str))
    {
        int len = strlen(str);
        for (int i = 0; i < len; i++)
        {
            if (isExist(str[i]))
            {
                ans[i] = key[str[i]];
            }
            else
            {
                ans[i] = str[i];
            }
        }
        ans[len] = '\0';
        printf("%s\n", ans);
    }
    return 0;
}

B:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3870

实验室退役队员亮GG在学java之余顺手过来A的题。

还没有详细看。

大致思路是将这些点按照二进制的第一个1出现在第几个位置来分类,然后搞一下就好啦。


更新:

记录每个数的二进制最高位在第几位,然后每个数扫一遍,扫他的二进制数。

若这个数的某一位为0,并且和他异或的小于他的数的二进制最高为1,则异或将大于这俩数,开个bit直接计数就行了。


需要注意的是,pos是可以到达0的,另外,pos是不能开到 1 << 32 的,因为爆了。。。。。。。。。。。。。。。

还有就是,LL。


代码(亮GG版):

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxN = 1e5 + 10;
int n, arr[maxN], ans[35][35], num[35];

int main()
{
    int ncase;
    cin>>ncase;
    while(ncase--)
    {
        long long result = 0;
        cin>>n;
        memset( ans, 0, sizeof(ans));
        memset( num, 0, sizeof(num));
        for(int i = 1; i <= n; ++i)
            scanf("%d", arr + i);
        sort( arr + 1, arr + n + 1);
        int edge = 2, t = 1;
        for(int i = 1; i <= n; )
        {
            while(arr[i] < edge && i <= n)
            {
                for(int j = t-1; j >= 1; j--)
                {
                    if((arr[i] & (1<<(j-1))) == 0)
                        ans[t][j]++;
                }
                num[t]++;
                i++;
            }
            t++;
            edge *= 2;
        }
        for(int i = 32; i >= 1; i--)
            for(int j = i - 1; j >= 1; j--)
            {
                long long t = ans[i][j];
                t *= num[j];
                result = result + t;
            }
        cout<<result<<endl;
    }
    return 0;
}


代码(update版):

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int bit[35];
int a[maxn];

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        memset(bit, 0, sizeof(bit));
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
            for (int j = 31; j >= 0; j--)
            {
                if (a[i] & (1 << j))
                {
                    bit[j]++;
//                    cout << a[i] << " " << j << endl;
                    break;
                }
            }
        }
        LL ans = 0;
        for (int i = 0; i < n; i++)
        {
            int pos = 31;///
            while (pos >= 0)
            {
                if (a[i] & (1 << pos))
                    break;
                pos--;
            }
            while (pos >= 0)///
            {
                if ((a[i] & (1 << pos)) == 0)
                {
                    ans += (LL)bit[pos];
                }
                pos--;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}


然后接下来我就开始搞D题,各种乱七八糟的想法。

于是就没做出来。

待更新D题。


D:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3872

真是遗憾的一题。

这道题目不会做折射出两点:首先,dp等于没练;其次,数学思维还是不行。

看完别人的题解瞬间就懂了的那种。

题意:

给n个数,找出他连续的子集,计算子集内独一无二的元素之和,最后求出所有前述特点子集的和。

解析:

看下面例子:

现在有元素,计算过程如下(括号中代表此元素出现次数)

例子1:

       2                 3                          4                         5                                   6                                   6                                   5                              

       2(1)            3(1)                    4(1)                     5(1)                              6(1)                              6(1)                             5(1)                          

                   2 + 3(2)              3 + 4(2)              4 + 5(2)                        5 + 6(2)                              6(2)                      6 + 5(2)                      

                                        2 + 3 + 4(3)        3 + 4 + 5(3)                 4 + 5 + 6(3)                       5 + 6(3)                      6 + 5(3)                          

                                                              2 + 3 + 4 + 5(4)          3 + 4 + 5 + 6(4)                 4 + 5 + 6(4)                      6 + 5(4)

                                                                                             2 + 3 + 4 + 5 + 6(5)          3 + 4 + 5 + 6(4)               4 + 6 + 5(5)

                                                                                                                                  2 + 3 + 4 + 5 + 6(5)         3 + 4 + 6 + 5(6)

                                                                                                                                                                             2 + 3 + 6 + 5(7)
例子2:

              2                     3                            4                       3                           2                            3   

             2(1)                3(1)                       4(1)                  3(1)                      2(1)                       3(1)

                                2+3(2)                  3+4(2)              4+3(2)                  3+2(2)                   2+3(2)

                                                          2+3+4(3)            3+4(3)              4+3+2(3)                   3+2(3)

                                                                                    2+3+4(4)             3+4+2(4)               4+3+2(4)

                                                                                                                  2+3+4(5)               3+4+2(5)    

                                                                                                                                                  2+3+4(5)


由例子就可以想到dp的过程了:

pos[num]数组代表num这个数字在之前出现的位置,状态转移方程:

dp[ i ]  =  dp[ i - 1 ]  + num  +  (  i - pos[num] - 1 ) * num。

注意LL。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 1e6 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int pos[maxn];
LL dp[maxn];

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
    #endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        memset(pos, 0, sizeof(pos));
        int n;
        scanf("%d", &n);
        dp[0] = 0;
        for (int i = 1; i <= n; i++)
        {
            int num;
            scanf("%d", &num);
            dp[i] = dp[i - 1] + num + num * (i - pos[num] - 1);
            pos[num] = i;
        }
        LL ans = 0;
        for (int i = 1; i <= n; i++)
        {
            ans += dp[i];
        }
        printf("%lld\n", ans);
    }
    return 0;
}


K:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5527

这是一道考英语考模拟的题目。

题目好长啊,但是读懂了模拟一下还是不难的。

题意:

首先输入ncase。

然后分别输入n,q,s,c,分别代表n个队伍,q台服务器,每个队伍初始分数s,以及检查时间点个数c。

然后再每个检查时间点,所知道的信息为:

          共发生了a次攻击:

                 每次攻击分别输入fr, to, ser,代表  fr  队经由服务器  ser  攻击了 to 队;

         被攻击成功的队伍的分数将减少 n - 1 分,攻击成功的队伍的分数增加的分数为 (n - 1 分 / 经过相同服务器攻击成功的队伍数)。


         对于每台服务器:

                    统计每个队是否正常维护当前服务器,若否为0,是为1;

                    增减分数规则同上;


        最后有k次询问,每次输出id为x的队伍的分数和排名。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 100 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
const double pi = acos(-1.0);
const double ee = exp(1.0);

struct Team
{
    int id, rank;
    double score;
} team[maxn];

bool attack[maxn][maxn][maxn];
bool success[maxn];

bool cmp_score(Team a, Team b)
{
    return a.score > b.score;
}

bool cmp_id(Team a, Team b)
{
    return a.id < b.id;
}

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int n, q, s, c;
        scanf("%d%d%d%d", &n, &q, &s, &c);
        for (int i = 0; i <= n; i++)
        {
            team[i].id = i;
            team[i].rank = 1;
            team[i].score = s;
        }
        while (c--)
        {
            int a;
            scanf("%d", &a);
            memset(attack, false, sizeof(attack));
            while (a--)
            {
                int fr, to, ser;
                scanf("%d%d%d", &fr, &to, &ser);
                attack[fr][to][ser] = true;
            }
            for (int ser = 1; ser <= q; ser++)
            {
                for (int to = 1; to <= n; to++)
                {
                    int cnt = 0;
                    for (int fr = 1; fr <= n; fr++)
                    {
                        if (attack[fr][to][ser])
                        {
                            cnt++;
                        }
                    }
                    if (cnt == 0)
                        continue;
                    double sum = (n - 1) / double(cnt);
                    team[to].score -= (n - 1);
                    for (int fr = 1; fr <= n; fr++)
                    {
                        if (attack[fr][to][ser])
                            team[fr].score += sum;
                    }
                }
            }
            for (int j = 0; j < q; j++)
            {
                memset(success, false, sizeof(success));
                int cnt = 0;
                for (int k = 1; k <= n; k++)
                {
                    int x;
                    scanf("%d", &x);
                    if (x)
                    {
                        success[k] = true;
                        cnt++;
                    }
                    else
                    {
                        team[k].score -= (n - 1);
                    }
                }
                double sum = (n - 1) / double(cnt);
                sum = sum * (n - cnt);
                for (int k = 1; k <= n; k++)
                {
                    if (success[k])
                    {
                        team[k].score += sum;
                    }
                }
            }
            sort(team + 1, team + n + 1, cmp_score);
            for (int j = 1; j <= n; j++)
            {
                if (j != 1)
                {
                    if (team[j - 1].score - team[j].score < eps)
                        team[j].rank = team[j - 1].rank;
                    else
                        team[j].rank = j;
                }
                else
                    team[j].rank = j;
            }
            sort(team + 1, team + n + 1, cmp_id);
            int k;
            scanf("%d", &k);
            while (k--)
            {
                int x;
                scanf("%d", &x);
                printf("%lf %d\n", team[x].score, team[x].rank);
            }
        }
    }
    return 0;
}


总结:

首先感觉还是需要思维的题目有点吃力,之后的训练是多练思维,dp,很明显亮GG的思维就比我好太多。

接下来还是,好好练吧,希望一百多天后能实现自己的梦想。

你可能感兴趣的:(The 12th Zhejiang Provincial Collegiate Contest(2015浙江省省赛))