现在的位置: 首页 > 综合 > 正文

HOJ 2014年“新生杯”

2018年02月21日 ⁄ 综合 ⁄ 共 4376字 ⁄ 字号 评论关闭

A.     统计数字(数位DP)

暴力的从1到n每个数字处理一遍是非常慢的,通过规律来计算得解可以大大优化。

例如n = 465的情况:

首先不考虑去掉前导0,那么从00到99,0~9每个数字出现的次数一是一样的,一共有100 *2个数次,平摊到每个数字则是都出现了20次;

同理,100到199,除了1多出现100次以外,0 2 3 4 5 6 7 8 9又出现了20次;

同理200~299,300~399;

400之后,不能再统计到499,统计的规模要缩小,换成400~409,410~419,420~429,…,450~459;

接着考虑460~465。

然后要去掉多余的前导零:

首先000有一个,然后001~009有9个,010~099有90个,再往后没有前导零了。

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;

int d[10];
int cnt[10];

int getdigit(int n)
{
    int ret = 0;
    while(n)
    {
        d[ret] = n % 10;
        n /= 10;
        ret++;
    }
    return ret;
}

int ten_pow(int k)
{
    int ret = 1;
    while(--k) { ret *= 10; }
    return ret;
}

void getans(int n)
{
    memset(cnt, 0, sizeof(cnt));
    int len = getdigit(n);
    for(int p = len - 1; p > 0; p--)
    {
        int k = ten_pow(p);
        for(int i = 0; i < 10; i++) cnt[i] += k * d[p] * p;
        for(int i = len - 1; i > p; i--) cnt[d[i]] += k * 10 * d[p];
        for(int i = 0; i < d[p]; i++) cnt[i] += k * 10;
//        for(int i = 0; i < 10; i++) printf("%d ", cnt[i]); cout << endl;
    }
    int w = n % 10;
    for(int i = 0; i <= w; i++) cnt[i]++;
    for(int i = len - 1; i > 0; i--) cnt[d[i]] += w + 1;
    cnt[0] -= len;
    int t = len, s = 9;
    while(t--)
    {
        cnt[0] -= t * s;
        s *= 10;
    }
    for(int i = 0; i < 10; i++) printf("%d\n", cnt[i]);
}

int main()
{
//    freopen("13124.in", "r", stdin);

    int n;
    while(~scanf("%d", &n))
    {
        getans(n);
    }
    return 0;
}

B.     青姬の爱恋

素数打表到maxn^(1/2),对于每个数n,找到较小的素数p,输出n / p。

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;

const int maxn = 1e5;
const int prin = 5e4;

int prime[prin];
///仅包含奇数,isprime[k]代表2*k+3
bool isprime[maxn >> 1];
int ptop = 0;

void sieve()
{
        memset(isprime, true, sizeof(isprime));
        prime[0] = 2;
        int sq = sqrt(maxn);
        for(int i = 3; i < maxn; i += 2)
                if(isprime[(i-3) >> 1])
                {
                        if(i <= sq + 3)
                        {
                                for(int j = i * i; j < maxn; j += 2 * i)
                                        isprime[(j-3) >> 1] = false;
                        }
                        prime[++ptop] = i;
                }
}

int main()
{
//    freopen("13125.in", "r", stdin);

    sieve();
    int n;
    while(~scanf("%d", &n))
    {
            int k = 0;
            while(n % prime[k] != 0 && k < ptop) { k++; }
            printf("%d\n", n / prime[k]);
    }
    return 0;
}

 

C.     买水果

整数规划,更简便的计算方法是用到五边形数定理。

什么是五边形数定理?

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

int p[110];

void init()
{
    p[0] = p[1] = 1;
    p[2] = 2;
    p[3] = 3;
    for(int i = 4; i < 110; i++)
    {
        p[i] = 0;
        int flag = 1;
        for(int j = 1; ; j++)
        {
            int p1 = j * (3 * j - 1) / 2;
            int p2 = j * (3 * j + 1) / 2;
            if(p1 > i && p2 > i) break;
            if(p1 <= i) p[i] = p[i] + flag * p[i - p1];
            if(p2 <= i) p[i] = p[i] + flag * p[i - p2];
            flag *= (-1);
        }
    }
}

int main()
{
    init();
    int t, n;
    while(scanf("%d", &n) != EOF)
    {

        printf("%d\n", p[n]);
    }
}

D.     小明和小红

Nim博弈类问题。在N符合条件的情况下,先手有必赢的策略。

假设N模4不为0,先手第一轮拿走N % 4颗糖果,后手每次拿x颗糖果,先手都拿4 – x颗,后手必输;

若N模4为0,先手必输。

 

E.      离散函数


绿色的线条表示非最优解,蓝色线条表示非法解,红色线条表示最优解。

对于每个点,一定是和它的相邻一个点的连线是最优解,所以只需要找相邻两个点的斜率最大值即可。

 

F.      熊大的学籍管理系统(hash)

将字符串通过hash函数处理成一个数,如果出现不同的字符串hash后得到同一个hash值,则用链表储存下来,查询的时候,只需搜该hash值对应的所有字符串。

什么是hash?

这个题还可以用c++里stl中的map来做,非常方便。

什么是map?

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
#define HASH 20011

typedef char Str[12];
Str id[HASH], na[HASH];

int n, head[HASH], next[HASH];

inline int BKDR_hash(char *str)
{
    int seed = 131;
    int hash = 0;
    while(*str) hash = hash * seed + (*str++);
    return (hash & 0x7fffffff) % HASH;
}

inline int add_hash(int s)
{
    int h = BKDR_hash(id[s]);
    next[s] = head[h];
    head[h] = s;
    return 1;
}

inline int srch(char *str)
{
    int h = BKDR_hash(str);
    int u = head[h];
    while(u)
    {
        if(strcmp(id[u], str) == 0) return u;
        u = next[u];
    }
    return -1;
}

Str idtmp, natmp, quary;

int main()
{
//    freopen("13129.in", "r", stdin);

    int N, Q, k;
    while(scanf("%d", &N) != EOF)
    {
        memset(id, 0, sizeof(id));
        memset(na, 0, sizeof(na));
        memset(head, 0, sizeof(head));
        memset(next, 0, sizeof(next));

        k = 1;
        for(int i = 0; i < N; i++)
        {
            scanf("%s%s", idtmp, natmp);
            if(srch(idtmp) != -1) printf("%s has existed!\n", idtmp);
            else
            {
                memcpy(id[k], idtmp, sizeof(id[k]));
                memcpy(na[k], natmp, sizeof(na[k]));
                add_hash(k);
                k++;
            }
        }
        scanf("%d", &Q);
        for(int i = 0; i < Q; i++)
        {
            scanf("%s", quary);
            int w = srch(quary);
            if(w == -1) printf("Can not find %s!\n", quary);
            else printf("%s\n", na[w]);
        }
    }
    return 0;
}

G.     她们会去哪里(几何)

纯计算。

 

H.     The Princess Number(暴力)

数据范围不够大,可以暴力做。数据范围大的时候,先对所有数排序,再进行统计即可。

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
#define MAXN 1000100

int cnt[MAXN], a[MAXN], na[MAXN], n;
int ans[MAXN], maxc, maxa, tot;

int l(int ai)
{
    return lower_bound(a, a + n, ai) - a;
}

int r(int ai)
{
    return upper_bound(a, a + n, ai) - a;
}

int main()
{
    int cas = 1;
    while(~scanf("%d", &n))
    {
        for(int i = 0; i < n; i++)
            scanf("%d", a + i);

        sort(a, a + n);
        maxa = a[n - 1];

        int now = 0;
        na[0] = a[0];
        for(int i = 0; i < n; i++)
            if(na[now] != a[i])
                na[++now] = a[i];
        now++;

        maxc = 0;
        memset(cnt, 0, sizeof(cnt));
        for(int i = 0; i < now; i++)
        {
            cnt[na[i]] = r(na[i]) - l(na[i]);
            maxc = max(maxc, cnt[na[i]]);
        }

        tot = 0;
        for(int i = 0; i <= maxa; i++)
            if(cnt[i] == maxc)
                ans[tot++] = i;

        printf("Case #%d: %d\n", cas++, tot);
        for(int i = 0; i < tot; i++)
        {
            if(i)
                printf(" ");
            printf("%d", ans[i]);
        }
        printf("\n");
    }
    return 0;
}


【上篇】
【下篇】

抱歉!评论已关闭.