2016.5.14【初中部 NOIP提高组 】模拟赛C总结

这次比赛成绩考得不咋地,第一次做C组就被水淹了,滚粗。。。QAQ。。。
一开始是抱着快点做完题去改题的心态去做比赛的,于是当时考场只打了前两题,而且还没有打拍,这很不应该,后两题只是略加思索,并没有实现。。。于是乎。。。就垫底了。。。

题解T1 小猫爬山
【NOIP2013模拟】小猫爬山 (Standard IO)
Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits

Description

Freda和rainbow饲养了N只小猫,这天们要去爬山 。经历了千辛万苦,小猫们 终于爬上了山顶,但是疲倦的它们再也不想徒步走下(呜咕 ><>< )。

Freda 和 rainbow只好 花钱让它们坐 索道 下山。 索道 上的缆车 最大承重量为 W,而 N只 小猫的重量分别是 C1、C2…… CN。当然,每辆缆车上的小猫重量之和不能超过W。每 租用一辆缆车 ,Freda 和 rainbow 就要付 1美元 ,所以他们想知道,最少需要付 多少美元才 能把这 N只小猫都运送下山?

Input

第一行 包含两个用空格隔开的整数, N和 W。

接下来 N行每一个整数,其中第 i+1行的整数 表示第 i只小猫的重量 Ci。

Output

输出 一个整数,最少需要多美元也就是辆缆车 。

Sample Input

5 1996

1

2

1994

12

29

Sample Output

2

Data Constraint

对于100%的数据,1<=N<=18,1<=Ci<=W<=10^8

乍一看,以为这道题是道DP,仔细想过后可以用迭代深搜实现。
首先,最好的情况自然是

sum=(Ci)W

所以我们可以从sum~18开始枚举车辆,进行深搜dfs。(因为最坏的情况也只是18辆)。
深搜过程我们可以用一个F数组记录每一种情况是否可行进行剪枝。

CODE

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define fd(i,a,b) for (int i=a;i>=b;i--)
#define N 20
using namespace std;

int c[N],F[N],sum=0,tot=0,n,w;
bool bz=false;

inline int read(int &number)
{
    char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') number=number*10+ch-'0',ch=getchar();
    return number;
}
bool cmp(int x,int y)
{
    return x>y;
}
void dg(int x)
{
    if (x==n+1)
    {
        bz=true;
        return; 
    }
    fo(i,1,tot)
        if (F[i]+c[x]<=w)
        {
            F[i]+=c[x];
            dg(x+1);
            F[i]-=c[x];
            if (bz) return;
        }
    return;
}

int main()
{
    read(n);read(w);
    fo(i,1,n) 
    {
        read(c[i]);
        sum+=c[i];
    }
    sort(c+1,c+n+1,cmp);
    for (tot=sum/w;tot<=18;tot++)
    {
        dg(1);
        if (bz)
        {
            printf("%d\n",tot);
            return 0;
        }
    }
    return 0;
}

T2
【NOIP2013模拟】KC看星 (Standard IO)
Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits

Description

“一闪一闪亮晶晶,满天都是小星星”

Kc吟唱着歌谣,躺在草坪上边想着她边看起了星星。Kc刚刚结识了笛卡尔这位好基友,认为他的坐标系非常神奇。于是他随机地选出了8颗星星,并且给它们标上了坐标。Kc又不甘寂寞,于是思考起一个问题:这八个点能否恰好构成一个正方形和一个矩形呢?

Input

输入文件包括1行16个数,表示8个星星的坐标,坐标绝对值不超过10000。

Output

输出文件第一行是”YES”或者”NO”。表示是否有解。

若有解则第二行依次输出正方形每个顶点的序号。第三行依次输出矩形每个顶点的序号。序号即为输入的顺序。

另外注意:因为kc是一个刁端的人,所以他要求第二行和第三行这八个数要字典序最小。

四点共线不能认为是正方形或矩形

Sample Input

0 0 10 11 10 0 0 11 1 1 2 2 2 1 1 2

Sample Output

YES

5 6 7 8

1 2 3 4

题解:
其实这道题只要模拟一下判断正方形和矩形的特性就可以了。注意斜着的正方形和矩形也算合法矩形,还有用c++同学和他的读入优化的同学请注意了,读入优化貌似不能读入负数,TMD的我就是这样被坑了。。。苍白无力。。

-正方形判定可以用四边相等,对角线相等。
-举行判定可以用两组对边分别相等,对角线相等。

CODE

#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define fd(i,a,b) for (int i=a;i>=b;i--)
#define N 10

using namespace std;
int a[N][3],b[N][N],c[N];
bool Mark[N];

void dg(int x)
{
    if (x==8+1)
    {
        bool bz1=false;
        bool bz2=false;
        if (b[c[1]][c[2]]==b[c[3]][c[4]])
        if (b[c[1]][c[3]]==b[c[2]][c[4]])
        if (b[c[1]][c[2]]==b[c[1]][c[3]])
        if (b[c[1]][c[4]]==b[c[2]][c[3]]) bz1=true;
        if (b[c[5]][c[6]]==b[c[7]][c[8]])
        if (b[c[5]][c[7]]==b[c[6]][c[8]])
        if (b[c[5]][c[8]]==b[c[6]][c[7]]) bz2=true;
        if (bz1 && bz2)
        {
            fo(i,1,3)
                fo(j,i+1,4) 
                if (c[i]>c[j])
                    swap(c[i],c[j]);
            fo(i,5,7)
                fo(j,i+1,8)
                if (c[i]>c[j]) swap(c[i],c[j]);
            printf("YES\n");
            fo(i,1,4) printf("%d ",c[i]);
            printf("\n");
            fo(i,5,8) printf("%d ",c[i]);
            exit(0);
        }
        return;
    }
    fo(i,1,8)
    if (!Mark[i])
    {
        c[x]=i;
        Mark[i]=true;
        dg(x+1);
        Mark[i]=false;
    }
}
int main()
{
    fo(i,1,8) scanf("%d",&a[i][1]),scanf("%d",&a[i][2]);
    memset(b,0,sizeof(b));
    fo(i,1,8)
        fo(j,1,8)
            if (i!=j)
               b[i][j]=sqrt((a[i][1]-a[j][1])*(a[i][1]-a[j][1])+(a[i][2]-a[j][2])*(a[i][2]-a[j][2]));
    fo(i,1,8)
    {
        Mark[i]=true;
        c[1]=i;
        dg(2);
        Mark[i]=false;
    } 
    printf("NO\n");
    return 0;
}

T3
【NOIP2013模拟】KC的瓷器 (Standard IO)
Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits

Description

KC来到了一个盛产瓷器的国度。他来到了一位商人的店铺。在这个店铺中,KC看到了一个有n(1<=n<=100)排的柜子,每排都有一些瓷器,每排不超过100个。那些精美的艺术品使KC一下心动了,决定从N排的商品中买下m(1<=m<=10000)个瓷器。

这个商人看KC的脸上长满了痘子,就像苔藓一样,跟精美的瓷器相比相差太多,认为这么精致的艺术品被这样的人买走艺术价值会大打折扣。商人感到不爽,于是规定每次取商品只能取其中一排的最左边或者最右边那个,想为难KC。

现在KC又获知每个瓷器的价值(用一个不超过100的正整数表示),他希望取出的m个商品的总价值最大。

Input

输入文件的第一行包括两个正整数n,m;

接下来2到n+1行,第i行第一个数表示第i排柜子的商品数量Si,接下来Si个数表示从左到右每个商品的价值。

Output

输出文件只有一个正整数,即m个商品最大的总价值。

Sample Input

输入1:

2 3

3 3 7 2

3 4 1 5

输入2:

1 3

4 4 3 1 2

Sample Output

输出1:

15

样例解释1:

取第一排的最左边两个和第二排的最右边那个。总价直为3+7+5=15;

输出2:

9

Data Constraint

对于10%的数据,Si=1,1<=i<=n。

对于另外10%的数据,n=1.

这是一道Dp题,题解是这样写的,
先预处理

take[i][j]
,表示从第i排中取出j个瓷器的最大价值,以及
a[i][j]
表示第i排前j个瓷器的总价值。
考虑对于每一排取出最左边的k个,那么剩下的j-k个就是最右边的,1<=k<=c。易得:
Take[i][j]=max(a[i][k]+a[i][c]a[i][cj+k])
,c表示第i排的瓷器数目。
接下来进行动态规划,
F[i][j]
表示从前i排取出j个的最大价值。
那么
F[i][j]=max(F[i1][jk]+take[i][k])

其实可以优化上述Dp,我们可以发现有一些状态是可以重复利用的,可以用滚动数组

F[2][M]
来存储状态表示第0…1个状态取M个瓷器的最大总价值。具体可参考标

CODE

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for (int i=a;i<=b;i++)
#define N 105
#define Maxn 10005
using namespace std;
int a[N],Pre[N],F[2][Maxn];
inline int read()
{
    char ch=getchar();
    int number=0;
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9') number=number*10+ch-'0',ch=getchar();
    return number;
}
int main()
{
    int n,m,tot=0;
    n=read();
    m=read();
    fo(i,1,n)
    {
        tot=read();
        fo(j,1,tot) a[j]=read();
        fill(Pre,Pre+N,0);
        fo(j,1,tot) Pre[j]+=Pre[j-1]+a[j];
        int tqy=(i&1);
        int cqy=((i+1)&1);
        fo(i,1,m) F[tqy][i]=F[cqy][i];
        fo(j,1,tot)
        {
            int tmp=0;
            fo(k,0,j) tmp=max(tmp,Pre[k]+Pre[tot]-Pre[tot-j+k]);
            fo(k,j,m) 
            {
                int lqy=F[cqy][k-j]+tmp;
                F[tqy][k]=max(F[tqy][k],lqy);
            }
        }
    }
    printf("%d",F[n&1][m]);
    return 0;
}

T4
【NOIP2013模拟】开心小屋 (Standard IO)
Memory Limits: 262144 KB Detailed Limits

Description

Kc来到开心小屋。开心小屋是用来提升心情的。在这个小屋中有n个房间,一些房间之间有门连通。从房间i到达房间j,心情值可以加上-10000<=Cij<=10000,当然Cij可能是负的。现在kc失恋了,所以他想要知道他是否可以在这个小屋中无限地增加他的心情值,也就是无限地绕着一个环走?

请帮kc求出最小的环需要经过的房间数,来使他的心情无限增加。

Input

第一行给出,1<=n<=300,1<=m<=5000。分别表示房间数及门的数量。

接下来m行,每行四个数:i,j,Cij,Cji

Output

输出文件包括一行,及最小的环需要经过的房间数。

保证不会出现自环及重边。

Sample Input

4 4

1 2 -10 3

1 3 1 -10

2 4 -10 -1

3 4 0 -3

Sample Output

4

样例解释:

1—>3—>4–>2–>1为最小的符合题意的环长度为4.

Data Constraint

对30%的数据,n<=10;

对60%的数据,,n<=100;

对100%的数据,n<=300;

题解:题目其实就是说给出无向图,要求求出节点数最小的正环长度。
可以用深搜来实现
正解说用弗洛伊德预处理出f[p][i][j],表示从i到j经过2^p条路径的最长路径。
接着二分答案t。检验答案和预处理类似,只需要考虑二进制位上为1的位置就可以了。用g[z][i][j]表示处理到第z个二进制位上为1的位置从i到j的最长路径,转移方程为:

g[z][i][j]=max(g[z1][i][k]+f[u][k][j])
。其中u表示第z个1是在n的二进制表示中的第u位。
时间复杂度O(n^3log^2n),会超时。 ~好复杂啊。。。

关于100%的数据,还没有理解透,等到时在更新。
至于CODE。。我还没打。。。年轻人自己思考吧。。。

这次比赛暴露出的问题有:
1、比赛没有对拍,导致该拿的分没有拿到,本来ac的两道题就飞了,没有仔细检查程序,对自己的程序太自信了。下次要好好应对每场比赛,每一道题,确保无误再交题。
2、考试太急了,还没有仔细思考就开打,导致后面思路凌乱。
3、要沉下心打题,遇到一些麻烦的打法要好好看,不能三心二意。
4、这次GG炸飞掉了,有很大原因是没有好好打题,轻视了这次比赛,最后还被别人虐了。。。狗带。。。
总结
1、每一场比赛都不能轻视
2、要好好总结,提高自己程序实践能力
3、心态要良好
4、%%%大神

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值