2016 PJ 题解

2016PJ题解

1、pencil

算法一

题目要求只能买一种包装的铅笔。可以发现,题目有整数倍的子任务,我们只需要看看3种包装每种最多要买多少袋同样包装的铅笔,再乘上它对应的价钱,取3者最小值即可

期望得分:50

 

算法二

针对于一算法。例:一包装每袋有2支铅笔,一袋3元,老师共需要3只铅笔.按照一方法做是不行的,因为买完后,还是有3 mod 2=1支铅笔,所以我们还要买多一个包装的。除此之外,其余同上。

期望得分:100

 

#include <cstdio>

#include <cstdlib>

#include <cmath>

#include <cstring>

#include <iostream>

#include <algorithm>

#include <vector>

#include <stack>

#include <queue>

#include <map>

 

using namespace std;

 

int n;

 

int main()

{

    freopen("pencil.in","r", stdin);

    freopen("pencil.out","w",stdout);

    intx, y, z, ans = 0x3f3f3f;

    for(inti = 1; i <= 3; i++)

    {

        scanf("%d5d",&x,&y);

        z= n / x;

        if(n % x != 0)

           z +=1;

        if(z* y < ans)

           ans = z * y;

    }

    printf("%d",ans);

    return0;

}

 

 

2、date

算法一

子任务中说date1=date2,所以我们直接判断题目输入的字符串是否构成回文,输出即可。

时间复杂度O(8)  期望得分:60

算法二

可以在题目两个日期之间date1~date2一天一天判断当天的日期是否构成回文,用字符串处理会超时,用算术法应能卡过去。

时间复杂度O(8999*12*31) 如果是算术法的话

期望得分:80~100

算法三

   因为年份是四位数,那么组成回文数时,回文数的左边一定是这个年份,枚举年份即可。根据回文数的左边,我们就可以推出右边的月和日。只需要判断月和日合不合法。

   1、日是否超过当前这个月的天数。

   2、月份只在1~12间,

   3、闰年的情况

   4、且当前日期是否在date1~date2之间。

   时间复杂度O(8999*4)  期望得分:100

 

#include<cstdio>

inta[13]={0,31,29,31,30,31,30,31,31,30,31,30,31},s,t,y1,m1,d1,y2,m2,d2,ans=0,y;

int f(int x)

{

    intj=0,k=1;

    if(x<10)k=10;

    for(;x;x/=10)j=j*10+(x%10);

    returnj*k;

}

int main()

{

    freopen("date.in","r",stdin);

    freopen("date.out","w",stdout);

    scanf("%d\n%d",&s,&t);

    for(inti = 1; i <= 12; i++)

      for(int j = 1; j <= a[i]; j++)

    {

        y=f(j)*100+f(i);

        if(y*10000+i*100+j>=s&&y*10000+i*100+j<=t&&f(y)==i*100+j)ans++;

    }

    printf("%d",ans);

}

 

3、port

算法1:直接根据题目模拟 空间或者时间会爆掉

    期望得分:60

 

算法2:采用队列:

用一个结构体队列存每个人来的时间和他的国籍,用一个vis数组存每个人来的次数,是第一次来sum便加一。

然后从前面第一个人开始扔下船,直到第一个人与当前这艘船相差没超过1天即可,每扔一个人便vis[此人国籍]减一,当这个人来的次数为0时,sum减一。

就这样,时间和空间都不会爆

   期望得分:100

 

#include<cstdio> 

#include<queue> 

using namespace std; 

struct p 

   int pt,pn;//存每个人的时间和国籍 

}; 

queue <p> ship; 

int n,vis[100005],sum; 

int main() 

   scanf("%d",&n); 

   while(n--) 

   { 

       int t,m,_n; 

       scanf("%d%d",&t,&m);//船来的时间和人数 

       for(int i=1;i<=m;i++) 

       { 

           scanf("%d",&_n); 

           p x; 

           x.pt=t; 

           x.pn=_n; 

           ship.push(x);//将这个人存入队列 

           vis[_n]++; 

           if(vis[_n]==1)//如果是第一次来 

                sum++; 

       } 

       while(1) 

       { 

           int a,b; 

           a=ship.front().pt,b=ship.front().pn;//检查这个人 

           if(t-a<86400)//与当前间隔没超过一天 

                break; 

           vis[b]--; 

           if(vis[b]==0) 

                sum--; 

           ship.pop();//把这个人扔出去 

       } 

       printf("%d\n",sum);//输出sum 

   } 

}

 

 

4 Magic

算法一

枚举四个数,符合条件累加方案数。

时间复杂度O(n^4或m^4) 期望得分:35~45

算法二

四个数是可以根据xb-xa=2(xd-xc)推出来的,所以减少一重循环。

时间复杂度(n^3或m^3) 期望得分:50~75

算法二

其实我们可以根据题目的三个条件画出一个数轴

①A<B<C<D

②(B-A)=2(D-C)

③3(B-A)<(C-B)

根据①条件:

根据②条件,我们可以得出,AB的距离是CD距离的两倍,设CD距离为i:

根据③条件,我们可以得出CB的距离大于AB的三倍,就是>2i*3=6i

我们可以枚举i,再枚举A的位置,枚举C的位置,再判断一下是否出现过ABCD,累加方案即可(Wx=Wy*Wz*Wa)另外三个出现次数。

时间复杂度O(**)   期望得分:80~85

4.3  算法三

分析题目,列出条件:Xa<Xb<Xc<Xd,Xb-Xa=2(Xd-Xc),Xb-Xa<(Xc-Xb)/3

遇到这种有条件的题,通常把图形画出来比较直观。



如图所示,若把d点确定,设c-d距离为i,则a,b的距离就是2i,则b,c的距离>3*(a-b)也就是>6i,总距离大于9i,那么我们的外层循环就枚举i,再枚举d的位置,d的方案数就等于(前面所有a的方案)*(前面所有b的方案)*(当前c的方案数),c的方案数=(前面所有a的方案)*(前面所有b的方案)*(当前d的方案数),同理,枚举a的位置,也可以得到a与b的方案数。

时间复杂度O(n)  期望得分:95~100

 

1. #include<cstdio>  

2. #define M 15005  

3. int a[M],b[M],c[M],d[M],w[3*M],h[3*M];  

4. int n,m,i,j,x,s;//s就是上面的y,累加和  

5. int main()  

6. {  

7.     scanf("%d%d",&n,&m);  

8.     for(i=1;i<=m;i++)  

9.     {  

10.         scanf("%d",&h[i]);  

11.         w[h[i]]++;  

12.     }  

13.     for(i=1;9*i<n;i++)//注意是总长度>9*i,边界一定要考虑无误,想通为什么  

14.     {  

15.         x=9*i+1;s=0;//设边界最好画个草图自己算一算  

16.         for(j=9*i+2;j<=n;j++)  

17.         {  

18.             s+=w[j-x]*w[j-x+2*i];  

19.             d[j]+=s*w[j-i];  

20.             c[j-i]+=s*w[j];  

21.         }  

22.         s=0;  

23.         for(j=n-x;j>=1;j--)//注意循环不能顺序,因为s的累加和会改变,a[j]会加上后面的c,d,而不是前面的  

24.         {  

25.             s+=w[j+x]*w[j+x-i];  

26.             a[j]+=s*w[j+2*i];  

27.             b[j+2*i]+=s*w[j];  

28.         }  

29.     }  

30.     for(i=1;i<=m;i++)  

31.         printf("%d %d %d %d\n",a[h[i]],b[h[i]],c[h[i]],d[h[i]]);  

32.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值