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;
}