2017.7.9 C组 总结

77 篇文章 0 订阅
36 篇文章 0 订阅

NO.1

题目描述:
给定n个数,{x1,x2,…,xn}要求从中选出至少一个数,至多n个数,使得乘积之和最大。

思路:强枚
记录下最大的小数,和小数的个数、”0”的个数
再做一波判断就好了

代码:

var  max,n,i,x,w,k:longint;
     ans:int64;
begin
  assign(input,'max.in');
  assign(output,'max.out');
  reset(input);
  rewrite(output);
  readln(n);
  ans:=1;
  max:=-10;
  for i:=1 to n do
    begin
      readln(x);
      if x<>0 then ans:=ans*x
      else inc(w);
      if x<0 then
        begin
         if max<x then max:=x;
         inc(k);
        end;
    end;
  if n=1 then begin write(ans); close(input); close(output); halt; end;
  if ans<0 then ans:=ans div max;
  if k mod 2=0 then write(ans)
  else if (w+k=n)and(k<n)and(k mod 2=1) then write('0')
       else if ans>0 then write(ans);
  close(input);
  close(output);
end.

NO.2

题目描述:
这里写图片描述
给定一个N位的数,将火柴棍重新排列后,能得到的最大的数是多少?
注意不能多出或者少一位, 火柴棍要全部用上.

思路:贪心
记录下每个数字需要的火柴数,从高位到低位,从大到小枚举,如果摆了这个数字后,后面全放8或全放2行不行(要注意:要恰好用完)

代码:

const f:array[0..9]of longint=(6,2,5,5,4,5,6,3,7,6);
var t,i,n,j,l,num:longint;
    c,kong:char;
    max:int64;
begin
  assign(input,'match.in');
  assign(output,'match.out');
  reset(input);
  rewrite(output);
  readln(t);
  for i:=1 to t do
    begin
      read(n);
      num:=n;
      read(kong);
      max:=0;
      l:=0;
      for j:=1 to n do begin read(c); max:=max+f[ord(c)-48]; end;
      while (2*num<=max)and(7*num>=max)and(l<=n)and(num>0)and(max>0) do
        begin
          inc(l);
          for j:=9 downto 0 do
            if (max-f[j]>=2*(num-1))and(7*(num-1)>=max-f[j])and(num>1)or(num=1)and(max=f[j])then
              begin
                dec(num);
                dec(max,f[j]);
                write(j);
                break;
              end;
        end;
      writeln;
    end;
  close(input);
  close(output);
end.

NO.3

题目描述:
Guyu Guo和Tube Lu正在玩一个游戏:Lu默想一个1和n 之间的数x,然后Guo尝试猜出这个数。
Guo能提出m个这样的问题: “未知数是否能被yi整除?”
游戏按照如下流程进行:Guo先给出他想问的全部m个问题,然后Lu对所有问题依次以“是”或“否”作答。得到m个问题的答案之后,Guo就要给出他的猜测。
Guo写了一个程序帮他以最优的方式提出这m个问题,现在他想知道在保证得到一个确定的答案下,最少可以问多少个问题,即m的最小值。但是Guo正忙于吃漂亮学姐送他的糖果而无暇改代码(送糖果的学姐十分多,以至于有许多糖果快要过期了),所以他找到了你,希望你来帮他解决这个问题。

思路:枚举+数学
由于一次性提出m个问题,然后得到回答,所以只能通过问题来确定最终可能的所有情况。
将n以内所有的质数求出来,用布尔类型存放
其实,推一推后,答案就是所有质数可能出现的次数,所以答案为所有质数的幂次<=n的个数

代码:

var n,i,j,ans:longint;
    x:qword;
    f:array[1..100000]of boolean;

begin
  assign(input,'game.in');
  assign(output,'game.out');
  reset(input);
  rewrite(output);
  readln(n);
  f[1]:=true;
  for i:=2 to n do
    if f[i]=false then
      for j:=2 to n div i do
        f[i*j]:=true;
  for i:=2 to n do
    if f[i]=false then
      begin
        x:=i;
        while x<=n do
          begin
            inc(ans);
            x:=x*i;
          end;
      end;
  write(ans);
  close(input);
  close(output);
end.

NO.4

题目描述:
Codefires round马上就要结束了!ZCC已经通过做题得到了C分。但他惊讶地发现,房间里的其他选手也都解决了最难的题。ZCC根据经验断定大多数的选手都会FST的!当然,除去rating最高的选手Memset137。在此之前,ZCC想要hack他们来使他的得分更高。除了ZCC,房间里有N个选手,他们已经被按照rating从小到大排序了(所以Memset137是排在第N个的选手)。当ZCC成功hack了第i个选手时,他会获得i分的收入。你可以假设ZCC hack技术高超,百发百中,可以hack除了Memset137和自己以外的所有选手,而且在此期间没有其他选手干扰。
由于ZCC有着谦虚的美德,他不想让自己的得分太高。ZCC想要知道,存在着多少种不同的选择一些人hack的方案,使得他的得分在L和R(C≤L ≤R< C+N)之间。
显然答案会很大,请输出答案对998244353取模后的结果。

思路:DP
首先,设f[i][j]为前i个数选了若干个的和为j的方案数,
那么容易推出f[i][j]=f[i-1][j]+f[i-1][j-i]
但是,这样做空间复杂度为O(NC),绝对会炸
所以,发现前m个数的和为m(m-1)/2
令m(m-1)/2=n,则m只有根号n级别,那么说明最多选根号n个数
故可以转成f[i][j]=f[i-1,j-i]+f[i,j-i] (为了i个数和为j的方案数)

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define MAXM 450
#define MOD 998244353
int n,c,l,r,dp[2][MAXN];
int main()
{
    freopen("hack.in","r",stdin);
    freopen("hack.out","w",stdout);
    scanf("%d%d%d%d",&n,&c,&l,&r);
    l-=c,r=min(r-c,n-1);
    memset(dp,0,sizeof(dp));
    dp[0][0] = 1;
    int ans=0;
    for(int i=1;(i+1)*i/2<=r;i++)
    {
        for(int j=(1+i)*i/2;j<=r;j++)
        {
            dp[i&1][j]=(dp[i&1][j-i]+dp[(i-1)&1][j-i])%MOD;
            if(l<=j&&j<=r) ans=(ans+dp[i&1][j])%MOD;
        }
        memset(dp[(i-1)&1],0,sizeof(dp[(i-1)&1]));
    }
    printf("%d\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值