noip2016普及组题解报告

来源:互联网 发布:直播间软件 编辑:程序博客网 时间:2024/06/06 19:12

当这份卷骗分拿了320分后,我不得不由衷地感叹一句:今年前两题简直太太太太太太太太太太太太太水了!如果你这张卷连200分都没有,我只想说,你还是去OJ上刷一刷Hello,World!和A+B Problem吧!

第一题:pencil AC >=O(1)
题目描述
P老师需要去商店买n支铅笔作为小朋友们参加NOIP的礼物。她发现商店一共有 3种包装的铅笔,不同包装内的铅笔数量有可能不同,价格也有可能不同。为了公平起 见,P老师决定只买同一种包装的铅笔。
商店不允许将铅笔的包装拆开,因此P老师可能需要购买超过n支铅笔才够给小朋 友们发礼物。
现在P老师想知道,在商店每种包装的数量都足够的情况下,要买够至少n支铅笔最少需要花费多少钱。
输入输出格式
输入格式:
输入的第一行包含一个正整数n,表示需要的铅笔数量。
接下来三行,每行用两个正整数描述一种包装的铅笔:其中第一个整数表 示这种包装内铅笔的数量,第二个整数表示这种包装的价格。
保证所有的7个数都是不超过10000的正整数。
输出格式:
输出一行一个整数,表示P老师最少需要花费的钱。

输入输出样例
输入样例#1:
57
2 2
50 30
30 27
输出样例#1:
54
输入样例#2:
9998
128 233
128 2333
128 666

输出样例#2:
18407
输入样例#3:
9999
101 1111
1 9999
1111 9999
输出样例#3:
89991
说明
铅笔的三种包装分别是:
•2支装,价格为2;
•50支装,价格为30;
•30支装,价格为27。
P老师需要购买至少57支铅笔。
如果她选择购买第一种包装,那么她需要购买29份,共计2x29 = 58支,需要花 费的钱为2x29 = 58。
实际上,P老师会选择购买第三种包装,这样需要买2份。虽然最后买到的铅笔数 量更多了,为30x2 = 60支,但花费却减少为27 x2 = 54,比第一种少。
对于第二种包装,虽然每支铅笔的价格是最低的,但要够发必须买2份,实际的 花费达到了 30 x 2 = 60,因此P老师也不会选择。
所以最后输出的答案是54。
【子任务】
子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试 只解决一部分测试数据。
每个测试点的数据规模及特点如下:
这里写图片描述
上表中“整倍数”的意义为:若为“K”,表示对应数据所需要的铅笔数量n—定是每种包装铅笔数量的整倍数(这意味着一定可以不用多买铅笔)。
好吧,我相信这题不用题解,直接上代码:

//pencil.cpp Noip2016 Junior Problem A#include <cstdio>int n, a[10], b[10];int min(int a, int b){    return a<b ? a : b;}int main(){//  freopen("pencil.in","r",stdin);//  freopen("pencil.out","w",stdout);    scanf("%d", &n);    for (int i = 1; i <= 3; i++)        scanf("%d %d", &a[i], &b[i]);    int res[5];    for (int i = 1; i <= 3; i++)    {        if (n%a[i] == 0) res[i] = (n / a[i])*b[i];        else if (n <= a[i]) res[i] = b[i];        else res[i] = ((n / a[i]) + 1)*b[i];    }    printf("%d", min(res[1], min(res[2], res[3])));// fclose(stdin); fclose(stdout);    return 0;}

第二题:date AC O(n)
题目描述
在日常生活中,通过年、月、日这三个要素可以表示出一个唯一确定的日期。
牛牛习惯用8位数字表示一个日期,其中,前4位代表年份,接下来2位代表月 份,最后2位代表日期。显然:一个日期只有一种表示方法,而两个不同的日期的表 示方法不会相同。
牛牛认为,一个日期是回文的,当且仅当表示这个日期的8位数字是回文的。现 在,牛牛想知道:在他指定的两个日期之间包含这两个日期本身),有多少个真实存 在的日期是回文的。
一个8位数字是回文的,当且仅当对于所有的i ( 1 <=i<= 8 )从左向右数的第i个 数字和第9-i个数字(即从右向左数的第i个数字)是相同的。
例如:
•对于2016年11月19日,用8位数字20161119表示,它不是回文的。
•对于2010年1月2日,用8位数字20100102表示,它是回文的。
•对于2010年10月2日,用8位数字20101002表示,它不是回文的。
每一年中都有12个月份:
其中,1、3、5、7、8、10、12月每个月有31天;4、6、9、11月每个月有30天;而对于2月,闰年时有29天,平年时有28天。
一个年份是闰年当且仅当它满足下列两种情况其中的一种:
1.这个年份是4的整数倍,但不是100的整数倍;
2.这个年份是400的整数倍。
例如:
•以下几个年份都是闰年:2000、2012、2016。
•以下几个年份是平年:1900、2011、2014。
输入输出格式
输入格式:
输入包括两行,每行包括一个8位数字。
第一行表示牛牛指定的起始日期。
第二行表示牛牛指定的终止日期。
保证date_i和都是真实存在的日期,且年份部分一定为4位数字,且首位数字不为0。
保证date1一定不晚于date2。

输出格式:
输出一行,包含一个整数,表示在date1和date2之间,有多少个日期是回文的。

输入输出样例
输入样例#1:
20110101
20111231
输出样例#1:
1
输入样例#2:
20000101
20101231
输出样例#2:
2
说明
【样例说明】
对于样例1,符合条件的日期是20111102。
对于样例2,符合条件的日期是20011002和20100102。
【子任务】
对于60%的数据,满足date1 = date2。
也是水题!
根据数据分析,这题直接暴力枚举能AC,于是我就打了下面的代码。。。
程序一发下来,我拿到洛谷上测,居然真的没有TLE,我可是一点优化都没打的呀!

//date.cpp Noip2016 Junior Problem B#include <iostream>#include <cstdio>using namespace std;bool run(int b)                     //判断是不是闰年{    if (b % 4 == 0 && (b % 100 != 0 || b % 400 == 0)) return true;    return false;}int date1, date2, ans = 0;bool hui()                          //判断是不是回文数{    if (date1 / 10000000 == date1 % 10        && (date1 / 1000000) % 10 == (date1 % 100) / 10        && (date1 / 100000) % 10 == (date1 % 1000) / 100        && (date1 / 10000) % 10 == (date1 % 10000) / 1000)  //尿性所致        return 1;    return 0;}void jia()                          //将日期加1天,我也懒得做优化了{    int nian = (date1 - date1 % 10000) / 10000, yue = (date1 % 10000) / 100, re = (date1 % 100);    switch (yue)    {    case 1:case 3:case 5:case 7:case 8:case 10:        if (re<31) re++;        else { re = 1; yue++; }        break;    case 12:        if (re<31) re++;        else { nian++; yue = 1; re = 1; }        break;    case 4:case 6:case 9:case 11:        if (re<30) re++;        else { yue++; re = 1; }        break;    case 2:        if (re<28) re++;        else {            if (run(nian) && re<29) re++;            else { yue++; re = 1; }        }        break;    }    date1 = nian * 10000 + yue * 100 + re;}int main(){//  freopen("date.in","r",stdin);//  freopen("date.out","w",stdout);    cin >> date1 >> date2;    if (date1 == date2)             //题目数据显示60% date1=date2    {        if (hui()) cout << 1;        else cout << 0;        return 0;    }    while (date1 <= date2)    {        if (hui()) ans++;        jia();                      //本来if(hui) 可以直接加一年的    }    cout << ans;    fclose(stdin); fclose(stdout);    return 0;}

第三题:port TLE(70) O(n^3)
题目描述
小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。
小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况;对于第i艘到达的船,他记录了这艘船到达的时间ti (单位:秒),船上的乘 客数星ki,以及每名乘客的国籍 x(i,1), x(i,2),…,x(i,k);。
小K统计了n艘船的信息,希望你帮忙计算出以每一艘船到达时间为止的24小时(24小时=86400秒)内所有乘船到达的乘客来自多少个不同的国家。
形式化地讲,你需要计算n条信息。对于输出的第i条信息,你需要统计满足 ti - 86400 < tp <= ti的船只p,在所有的x(p,j)中,总共有多少个不同的数。
输入输出格式
输入格式:
第一行输入一个正整数n,表示小K统计了 n艘船的信息。
接下来n行,每行描述一艘船的信息:前两个整数ti和ki分别表示这艘船到达海港的时间和船上的乘客数量,接下来ki个整数x(i,j)表示船上乘客的国籍。
保证输入的ti是递增的,单位是秒;表示从小K第一次上班开始计时,这艘船在第 ti 秒到达海港。
保证:
1<=n<=100000,
∑ki<=3*100000,
1<=x[i][j]<=100000,
1<=t[i-1]<=ti<=10^9
其中∑ki表示所有的ki的和。
输出格式:
输出n行,第i行输出一个整数表示第i艘船到达后的统计信息。
输入输出样例
输入样例#1:
3
1 4 4 1 2 2
2 2 2 3
10 1 3
输出样例#1:
3
4
4
输入样例#2:
4
1 4 1 2 2 3
3 2 2 3
86401 2 3 4
86402 1 5
输出样例#2:
3
3
3
4
说明
【样例解释1】
第一艘船在第1秒到达海港,最近24小时到达的船是第一艘船,共有4个乘客, 分别是来自国家4,1,2,2,共来自3个不同的国家;
第二艘船在第2秒到达海港,最近24小时到达的船是第一艘船和第二艘船,共有 4 + 2 = 6个乘客,分别是来自国家4,1,2,2,2,3,共来自4个不同的国家;
第三艘船在第10秒到达海港,最近24小时到达的船是第一艘船、第二艘船和第 三艘船,共有4+ 2+1=7个乘客,分别是来自国家4,1,2,2,2,3,3,共来自4个不同 的国家。
【样例解释2】
第一艘船在第1秒到达海港,最近24小时到达的船是第一艘船,共有4个乘客,分别是来自国家1,2,2,3,共来自3个不同的国家。
第二艘船在第3秒到达海港,最近24小时到达的船是第一艘船和第二艘船,共有4+2=6个乘客,分别是来自国家1,2,2,3,2,3,共来自3个不同的国家。
第三艘船在第86401秒到达海港,最近24小时到达的船是第二艘船和第三艘船,共有2+2=4个乘客,分别是来自国家2,3,3,4,共来自3个不同的国家。
第四艘船在第86402秒到达海港,最近24小时到达的船是第二艘船、第三艘船和第四艘船,共有2+2+1=5个乘客,分别是来自国家2,3,3,4,5,共来自4个不同的国家。
【数据范围】
这里写图片描述
好吧,我选择了70%(实战经验还不足!)
直接枚举!!!!

//port.cpp Noip2016 Junior Problem C#include <cstdio>#include <iostream>#include <cstring>#define maxn 10002using namespace std;const int tl = 86400;int n, t[maxn], k[maxn], te = 1, book[maxn], x[maxn][maxn];int main(){//  freopen("port.in","r",stdin);//  freopen("port.out","w",stdout);    cin >> n;    for (int i = 1; i <= n; i++)    {        memset(book, 0, sizeof(book));        int res = 0;        cin >> t[i] >> k[i];        for (int j = 1; j <= k[i]; j++)            cin >> x[i][j];        for (int j = te; j <= i; j++)            if (t[i] - t[j]<tl)                for (int l = 1; l <= k[j]; l++)                {                    if (book[x[j][l]] == 0) { book[x[j][l]] = 1; res++; }                }            else te = j + 1;            cout << res;            if (i != n) cout << endl;    }//  fclose(stdin); fclose(stdout);    return 0;}
//正解在这里!花了半小时才想出来//port(new).cpp Noip2016 Junior Problem C#include <cstdio>#include <iostream>#include <queue>using namespace std;struct visitor          //结构体储存旅客信息{    int time, country;    visitor operator = (const visitor& x)    {        time = x.time;        country = x.country;        return *this;    }};queue <visitor> boat;  //创建队列int n, t, k, ans = 0, book[100001];int main(){//  freopen("port.in", "r", stdin);//  freopen("port.out", "w", stdout);    cin >> n;    for (int i = 0; i < n; i++)    {        cin >> t >> k;        for (int j = 0; j < k; j++)        {            visitor x;            int c;            cin >> c;            x.time = t;            x.country = c;            if (!book[c])                ans++;            boat.push(x);            book[c]++;        }        visitor q = boat.front();        while (q.time <= t - 86400)        {            book[q.country]--;            if (!book[q.country])                ans--;            boat.pop();            q = boat.front();        }        cout << ans << endl;    }//  fclose(stdin); fclose(stdout);    return 0;}

第四题:magic TLE(50) O(n^4)
题目描述
六十年一次的魔法战争就要开始了,大魔法师准备从附近的魔法场中汲取魔法能量。
大魔法师有m个魔法物品,编号分别为1,2,…,m。每个物品具有一个魔法值,我们用Xi表示编号为i的物品的魔法值。每个魔法值Xi是不超过n的正整数,可能有多个物品的魔法值相同。
大魔法师认为,当且仅当四个编号为a,b,c,d的魔法物品满足xa

//magic.cpp Noip2016 Junior Problem D#include <iostream>#include <algorithm>#include <cstdio>using namespace std;int main(){//  freopen("magic.in","r",stdin);//  freopen("magic.out","w",stdout);    int n, m, x[40005], a, b, c, d, res[40005][5];    cin >> n >> m;    for (int i = 0; i<m; i++)        cin >> x[i];    for (a = 0; a < m; a++)        for (b = 0; b < m; b++)            if (x[a] < x[b])                for (c = 0; c<m; c++)                    if (x[b] < x[c] && x[b] - x[a] < (float(x[c] - x[b])) / 3)                        for (d = 0; d<m; d++)                            if (x[c]<x[d] &&x[b] - x[a] == 2 * (x[d] - x[c]))                            {                                res[a][1]++; res[b][2]++; res[c][3]++; res[d][4]++;                            }    for (int i = 0; i<m; i++)    {        for (int j = 1; j<5; j++)        {            cout << res[i][j];            if (j != 4) cout << ' ';        }        if (i != m - 1) cout << '\n';    }//  fclose(stdin); fclose(stdout);    return 0;}//正解如下://magic.cpp noip2016 Junior Problem D#include <cstdio>int n, m, i, j, x, y, s[40005], f[40005], a[40005], b[40005], c[40005], d[40005];int main(){    scanf("%d %d", &n, &m);    for (i = 1; i <= m; i++)    {        scanf("%d", &s[i]);        f[s[i]]++;    }    for (i = 1; i <= n / 9; i++)    {        x = 9 * i + 1;        y = 0;        for (j = 9 * i + 2; j <= n; j++)        {            y = y + f[j - x] * f[j - x + 2 * i];            d[j] += y*f[j - i];            c[j - i] += y*f[j];        }        x = 8 * i + 1; y = 0;        for (j = n - 9 * i - 1; j >= 1; j--)        {            y += f[j + x] * f[j + x + i];            a[j] += y*f[j + 2 * i];            b[j + 2 * i] += y*f[j];        }    }    for (i = 1; i < m; i++)        printf("%d %d %d %d\n", a[s[i]], b[s[i]], c[s[i]], d[s[i]]);    printf("%d %d %d %d", a[s[i]], b[s[i]], c[s[i]], d[s[i]]);}
0 0
原创粉丝点击