2017.1.20 精英班试题讲解

来源:互联网 发布:java如何输出数组的值 编辑:程序博客网 时间:2024/05/18 00:28
选拔(select)

数字(number)

测试(quiz)

 

选拔(select)

Time Limit:1000ms  Memory Limit:128MB

 

题目描述

LYK对n个女生有好感。第i个女生的身高为ai。

LYK要在这些女生中选拔出一个女生来作为他的女朋友。选拔当然要排队咯。于是LYK想让这n个女生排成一行。

但LYK觉得对于两个身高相同的女生,谁排在前谁排在后其实让整个队列看上去并没有什么差别。

LYK想知道有多少个有差别的队列。

 

输入格式(select.in)

第一行一个数n表示女生个数。

第二行有n个数ai表示第i个女生的身高。

 

输出格式(select.out)

一个数表示答案。

 

输入样例

3

1 2 2

 

输出样例

3

 

数据范围

对于40%的数据n<=5,。

对于60%的数据n<=20。

对于80%的数据n<=1000。

对于100%的数据n<=10000,1<=ai<=n。

 

1 2 3 4 5   5!

1 1 3 4 5   5!/2!

1 1 1 3 4   5!/3!

1 1 1 1 3   5!/4!

1 1 2 2 3   5!/2!/2!

分子分母都分解质因子,删去相同的部分。

压位,一般压9位

 

2 100
30+30+30+10
2^30 2^30 2^30 2^10

 

#include<cmath>#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;const int X=1000000000;int f[50005],a[50005],i,n,A,v[50005],j,sum,k;long long ans[50005];int main(){    freopen("select.in","r",stdin);    freopen("select.out","w",stdout);    scanf("%d",&n);    for (i=1; i<=n; i++)    {        scanf("%d",&A);        a[A]++;    }    for (i=1; i<=n; i++) f[i]++;    for (i=1; i<=n; i++)        for (j=1; j<=a[i]; j++) f[j]--;    for (i=2; i<=n; i++)    {        if (!v[i])        for (j=i+i; j<=n; j+=i)        {            v[j]=1; sum=0;            k=j; while (k%i==0) k/=i,sum++;            //cout<<i<<' '<<j<<' '<<sum<<endl;            f[i]+=sum*f[j];        }    }    ans[1]=1; ans[0]=1;    for (i=2; i<=n; i++)        if (!v[i])        while (f[i])        {            f[i]--;            long long p=i; while (f[i] && p*i<=1000000000) {p*=i; f[i]--;}            for (j=1; j<=ans[0]; j++) ans[j]*=p;            for (j=1; j<ans[0]; j++) if (ans[j]>=10) {ans[j+1]+=ans[j]/X; ans[j]%=X;}            while (ans[ans[0]]>=X) {ans[0]++; ans[ans[0]]=ans[ans[0]-1]/X; ans[ans[0]-1]%=X;}        }    cout<<ans[ans[0]];    for (i=ans[0]-1; i>=1; i--)    {        j=X/10;        while (ans[i]<j) {printf("0"); j/=10;}        if (ans[i]) printf("%d",ans[i]);    }    return 0;}
这场故梦里

 

 

数字(number)

Time Limit:2000ms   Memory Limit:128MB

 

题目描述

LYK收到了n个数字作为新年礼物,第i个数字的值为ai。

除了这些数字,还有一个信封,上面写着:“如果你能从这n个数中选出k个数使得它们的和为奇数,那么我将会满足你一个愿望!”

LYK觉得这不可能,此处必有玄机,于是它想在满足信封里的要求的情况下满足选出的数字的和最大。LYK想知道最大是多少。

当然不止这一年LYK收到了礼物,以后的每一年都会有这样的一个礼物,具体的,总共有m年。神奇的是这些数字并没有发生变化,而k发生了变化,LYK想知道所有年的答案是多少。

可能会存在写信人在骗它,也就是说不存在一个可行的方案,此时输出-1就可以了。

 

输入格式(number.in)

第一行一个数n表示LYK收到的数字个数。

第二行n个数ai表示每个数字。

第三行一个数m。

第四行m个数表示每一年的k值。

 

输出格式(number.out)

m行,每行输出一个答案。

 

输入样例

3

1 2 2

3

1 2 3

 

输出样例

1

3

5

 

数据范围

对于30%的数据n,m<=100。

对于60%的数据n,m<=1000。

对于另外10%的数据所有ai均为奇数。

对于再另外10%的数据所有ai均为偶数。

对于90%的数据n,m<=100000。

对于100%的数据n,m<=1000000,1<=ai<=n+2。

 

Note:

想拿满分的同学建议使用读入优化。

以下是读入优化模板:

void read(int &A)

{

    char r; A=0;

    for (r=getchar(); r<'0' || r>'9'; r=getchar());

    for (;r>='0' && r<='9'; r=getchar()) A=A*10+r-'0';

}

特判:

全是偶数,都不行。

全是奇数,k是偶数,都不行;k是奇数,输出最大奇数和。

贪心:

从大到小排序,找尽可能靠前的,1……k和为奇数则为答案,和为偶数则不符合条件,从前面删掉一个偶数,后面加一个奇数;或从前面删掉一个奇数,后面加一个偶数。

只能删一个加一个。

对两种情况进行讨论。

—————A—————|—————B—————

最大pos=1             界线=k                   最小

找到A中距离界线最近的偶数,与B中距离界线最近的奇数交换,计算一个答案

找到A中距离界线最近的奇数,与B中距离界线最近的偶数交换,计算另一个答案

输出最大的值

 

f[i]表示1~i中最靠右的偶数
if (a[i]%2==0) f[i]=a[i]; else
f[i]=(1~i-1中最靠右的偶数)f[i-1]
f[i]表示1~i中最靠右的奇数
if (a[i]%2==1) f[i]=a[i]; else
f[i]=(1~i-1中最靠右的奇数)f[i-1]
g[i]表示i~n中最靠左的偶数
if (a[i]%2==0) g[i]=a[i]; else
g[i]=(i+1~n中最靠左的偶数)g[i+1]
g[i]表示i~n中最靠左的奇数
if (a[i]%2==1) g[i]=a[i]; else
g[i]=(i+1~n中最靠左的奇数)g[i+1]

 

#include<cmath>#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;const int N=1000005;int a[N],F0[N],i,n,F1[N],F2[N],F3[N],m,A;long long ans[N],sum;int cmp(int i,int j) {return i>j;}void read(int &A){    char r; A=0;    for (r=getchar(); r<'0' || r>'9'; r=getchar());    for (;r>='0' && r<='9'; r=getchar()) A=A*10+r-'0';}int main(){   // read(n);// cout<<n<<endl;    freopen("number.in","r",stdin);    freopen("number.out","w",stdout);    scanf("%d",&n);    for (i=1; i<=n; i++) read(a[i]);    sort(a+1,a+n+1,cmp);    for (i=1; i<=n; i++)    {        if (a[i]%2==0) F0[i]=i; else F0[i]=F0[i-1];        if (a[i]%2==1) F1[i]=i; else F1[i]=F1[i-1];    }    for (i=n; i>=1; i--)    {        if (a[i]%2==0) F2[i]=i; else F2[i]=F2[i+1];        if (a[i]%2==1) F3[i]=i; else F3[i]=F3[i+1];    }    for (i=1; i<=n; i++)    {        sum+=a[i]; ans[i]=-1;        if (sum%2==1) ans[i]=sum; else        {            if (F0[i] && F3[i+1]) ans[i]=max(ans[i],sum-a[F0[i]]+a[F3[i+1]]);            if (F1[i] && F2[i+1]) ans[i]=max(ans[i],sum-a[F1[i]]+a[F2[i+1]]);        }    }    scanf("%d",&m);    while (m--)    {        scanf("%d",&A);        printf("%I64d\n",ans[A]);    }    return 0;}
孤桨声远荡

 

测试(quiz)

Time Limit:1000ms   Memory Limit:128MB

 

题目描述

随着WC的到来,LYK每天都在学习着新的知识。俗话说,比赛成绩=实力*经验。LYK相信它已经拥有了足够强的实力获得WC金牌。只要积累充足的经验,就能够获得强大的精神能量AK今年的WC!

于是LYK找来了n道题目想给自己做一个测试,对于第i道题目有ai分。LYK非常强大,能轻易地做出所有题目,但它觉得这样十分没意思。于是它给自己出了一道题目。

假如存在一个虚拟对手LYK2,对于每道题目它有50%的几率能够做对,做对一道题目能够获得其分数,做不对则得到0分。

LYK想知道,至少获得多少分数,使得至少有p的概率分数不低于LYK2。

 

输入格式(quiz.in)

第一行两个数n,p。

接下来一行n个数表示ai。

 

输出格式(quiz.out)

一个数表示答案。

 

输入样例

2 0.6

1 2

 

输出样例

2

 

数据范围

对于20%的数据n<=5,ai<=1000。

对于40%的数据n<=30,ai<=1000。

对于60%的数据n<=60,ai<=1000。

对于另外10%的数据n<=25,ai<=10^9。

对于再另外10%的数据n<=35,ai<=10^9。

对于再再另外20%的数据p为整数,n<=60,ai<=10^9。

对于100%的数据0<=p<=1,p小数点后至多两位,2<=n,ai>=1 。

分数至少为2^n*p,上取整 = k,对方有2^n种分数

->在2^n找第k小   n<=35   与two point 的做法类似

拿满分要用动规   dp[i]表示分数为i的方案总数

 

#include <cmath>#include <cstdio>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;const int N=(1<<20)+5;long long c[N],b[N],F,l,r,mid,sum,dp[100005];int cntc,cntb,n,i,a[105],j;double Q,p;const double eps=1e-7;void dfs(int x,long long y){    if (x==mid+1) {c[++cntc]=y; return;}    dfs(x+1,y);    dfs(x+1,y+a[x]);}void dfs2(int x,long long y){    if (x==n+1) {b[++cntb]=y; return;}    dfs2(x+1,y);    dfs2(x+1,y+a[x]);}int cmp(long long a,long long b) {return a<b;}long long work(long long x){    long long ans=0;    int j=cntc;    for (int i=1; i<=cntc; i++)    if (b[1]+c[i]>x) {j=i-1; break;}    for (int i=1; i<=cntb; i++)    {        ans+=j;        while (j && b[i+1]+c[j]>x) j--;    }    return ans;}int main(){    freopen("quiz.in","r",stdin);    freopen("quiz.out","w",stdout);    scanf("%d%lf",&n,&p);    for (i=1; i<=n; i++) scanf("%d",&a[i]);    for (i=1; i<=n; i++) sum+=a[i];    if (p<eps) {puts("0"); return 0;}    if (p>1-eps) {cout<<sum<<endl; return 0;}    Q=(1ll<<n)*p;    if (Q-(long long)Q<eps) F=(long long)Q; else F=(long long)Q+1;    if (n<=40)    {        mid=n/2;        dfs(1,0);        dfs2(mid+1,0);        sort(b+1,b+cntb+1,cmp);        sort(c+1,c+cntc+1,cmp);        l=0; r=sum; mid=(l+r)/2;        while (l<=r)        {            if (work(mid)<F) {l=mid+1; mid=(l+r)/2;} else {r=mid-1; mid=(l+r)/2;}        }        cout<<l<<endl;        return 0;    }    dp[0]=1;    for (i=1; i<=n; i++)        for (j=sum; j>=a[i]; j--)          dp[j]+=dp[j-a[i]];    for (i=1; i<=sum; i++) dp[i]+=dp[i-1];    for (i=0; i<=sum; i++) if (dp[i]>=F) {cout<<i<<endl; return 0;}}
去他乡,遗忘。

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 唯品会商品有的不支持退换货怎么办 苹果手机和平板电脑共享怎么办 ipad被锁定了停用了怎么办 word文档被锁定不能编辑怎么办 苹果平板id忘了怎么办 ipad有id锁怎么办换主板 ipad刷机后忘记id密码怎么办 网购买东西手机号错了怎么办? 淘宝卖家虚假交易违规怎么办 好朋友问我借身份证开网店怎么办 为什么淘宝点开就跳过打不开怎么办 刹车油进眼睛里怎么办 眼睛被uv灯刺伤怎么办 眼睛被uv灯伤了怎么办 洗手台靠不到墙怎么办 加盟天猫优品不想干了怎么办 口袋侦探点开始就闪退怎么办 淘宝号被监控了怎么办 excel表格中把字体变细怎么办 wps方框中打字打不上怎么办 蘑菇街里面买东西受骗了怎么办? 淘宝买家号账户体检中心违规怎么办 支付宝充错手机账号怎么办 美团恶意差评怎么办 买家好评后追加差评怎么办 宝贝吃了一个金币怎么办 店铺微淘等级l1怎么办 淘宝占内存2个g怎么办 淘宝太占空间了怎么办 支付宝占内存大怎么办 苹果手机储存空间不足怎么办 小米平板电脑储存空间不足怎么办 ipad2很卡反应慢怎么办 ipadmini很卡反应慢怎么办 手机酷狗音乐文件不支持怎么办 2018款ipad闪退怎么办 ipad开不了机了怎么办 淘宝盖楼上限了怎么办 交了学费做微淘客却加不到人怎么办 微淘客交首付不想做了怎么办 蚂蚁微客二维码推广怎么办