2017-8-31 NOIP模拟赛(校内测)

Posted Soda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017-8-31 NOIP模拟赛(校内测)相关的知识,希望对你有一定的参考价值。

可接受序列

【题目描述】

让计算机这样读入一列非负整数:

1、读入数T。                   

2、接着往下读入T个数。

3、如果数列读完了,则停止,否则,转到1。

但是,往往会出现这样的问题:执行第2步时,数列已经没有T个数了。如果这样,我们称这个数列是“不可接受的”,否则,称它是“可接受的”。我们需要用最少的步数把一个数列变成“可接受的”,一步是指:

1、把数列中的某一个数加1。

2、把数列中的某一个数减1。

【输入格式】

第一行有一个数N (1<=N<=1000000),表示数列的长度,接下来有n行,描述这个数列,每一行有一个非负整数(不超过1000000)。

【输出格式】

仅一个数,表示最少的步数。

【输入输出样例】

sequence.in

sequence.out

7

3

1

2

3

4

5

6

1

【数据规模】

对于50%的数据,N≤1,000;

对于80%的数据,N≤100,000;

对于100%的数据,N≤1,000,000。

技术分享
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
using namespace std;
int n,a[1000010];
long long ans=9999999999;
void dfs(int pos,long long cnt){
    if(cnt>=ans)return;
    //if(pos>n)return;
    if(pos==n+1){
        ans=min(ans,cnt);
        return;
    }
    if(pos==n){
        dfs(pos+1,cnt+a[pos]);
        return;
    }
    for(int i=0;i+pos<=n+1;i++){
        int step=abs(a[pos]-i);
        dfs(pos+i+1,cnt+step);
    }
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    dfs(1,0);
    cout<<ans;
    return 0;
}
20分 暴力深搜

 

 

促销

【题目描述】

    某某商场搞了一个促销活动,促销活动以以下方式进行:

  1. 一个想要参加活动的顾客将他的发票扔进抽奖箱里。
  2. 在每天的最后,从抽奖箱里抽出两张发票:

a)       金额最大的发票a

b)       金额最小的发票b

  1. 金额最大的发票的持有者得到a-b的奖金。

每天被抽出的发票都不会再被放回抽奖箱里。

你想知道促销活动结束时一共付出了多少奖金。

【输入格式】

    第一行一个N,促销进行的天数;

    接下来N行,第一个数是一个ki,表示第i天收到的发票数;接下来ki个数,每个数是一个发票的金额。

【输出格式】

    一个数,整个促销活动过程中一共付出了多少奖金。

【输入输出样例】

promotion.in

promotion.out

5

3 1 2 3

2 1 1

4 10 5 5 1

0

1 2

19

【数据规模】

    对于30%的数据,发票总数M不超过2000;

    对于另外20%的数据,每张发票的金额不超过2000;

    对于100%的数据,发票总数M不超过1000000,每张发票的金额不超过1000000。

技术分享
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
priority_queue<int>heap1;
priority_queue<int>heap2;
int n;
long long ans;
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("promotion.in","r",stdin);
    freopen("promotion.out","w",stdout);
    scanf("%d",&n);
    int x,y;
    for(int i=1;i<=n;i++){
        scanf("%d",&x);
        for(int j=1;j<=x;j++){
            scanf("%d",&y);
            heap1.push(y);
            heap2.push(-y);
        }
        int a,b,a1,b1;
        a=heap1.top();heap1.pop();
        b=heap2.top();heap2.pop();
        if(a!=-b){
            ans+=a+b;
            continue;
        }
        a1=heap1.top();heap1.pop();
        b1=heap2.top();heap2.pop();
        if(a+b1>b+a1){
            heap1.push(a1);
            heap2.push(b);
            ans+=a+b1;
            continue;
        }
        else {
            heap1.push(a);
            heap2.push(b1);
            ans+=a1+b;
            continue;
        }
    }
    cout<<ans;
    return 0;
}
100分 两个堆

亲和数

【题目描述】

某一天,老徐看了一本趣味数学书,上面提到了亲和数:定义数对 (x,y) 为亲和数对当且仅仅当x、y为不同正整数,且x、y各自的所有非自身正因子之和等于另一个数。例如 (220,284) 和 (284,220) 都是亲和数对,因为:220的所有非自身正因子之和为:1 + 2 + 4 + 5 + 10 + 11 + 20 + 22 + 44 + 55 + 110 = 284。284的所有非自身正因子之和为:1 + 2 + 4 + 71 + 142 = 220

数对 (x,y ) 跟 (y,x) 被认为是同一数对,所以我们只考虑 x<y 的情况。

老徐对某个范围内的亲和数对的数量非常感兴趣,所以希望你能帮她编写一个程序计算给定范围内的亲和数对的数量。给定一个范围A到B,如果A≤ x ≤ B,则我们称 (x,y)在范围[A,B]内。

【输入格式】

从文件的第一行分别读入正整数A和B,其中A、B满足

     1 ≤ A ≤ B ≤ 108  且 B-A ≤ 105

【输出格式】

输出文件只有一行,就是[A,B]内亲和数对的数量

【输入输出样例】

amicable.in

amicable.out

200 1200

2

注:[200,1200] 内的数对只有两个,分别是(220,284)和(1184 1210)

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a,b,bit[10],len,q[10];
bool pan(int num){
    int sum=1;
    for(int i=2;i*i<=num;i++){
        if(num%i==0&&i*i!=num)sum+=i+num/i;
        if(i*i==num)sum+=i;
    }
    if(sum<=num)return 0;
    for(int i=2;i*i<=sum;i++){
        if(sum%i==0&&i*i!=sum)num-=i+sum/i;
        if(i*i==sum)num-=i;
        if(num<0)return 0;
    }
    if(num==1)return 1;
}
int shu(int pos,int num,bool limit){
    if(pos==len+1){
        if(pan(num))return 1;
        return 0;
    }
    int end=limit?bit[pos]:9;
    int ans=0;
    for(int i=0;i<=end;i++){
        ans+=shu(pos+1,num*10+i,limit&&i==end);
    }
    return ans;
}
int dp(int x){
    memset(q,0,sizeof(q));
    memset(bit,0,sizeof(bit));
    len=0;
    while(x){
        q[++len]=x%10;
        x/=10;
    }
    for(int i=len,j=1;i>=1;i--,j++)bit[i]=q[j];
    return shu(1,0,1);
}
int main(){
    //freopen("Cola.txt","r",stdin);
    freopen("amicable.in","r",stdin);
    freopen("amicable.out","w",stdout);
    scanf("%d%d",&a,&b);
    cout<<dp(b)-dp(a-1);
    return 0;
}
50分 数位dp(记忆化没写成)

 

以上是关于2017-8-31 NOIP模拟赛(校内测)的主要内容,如果未能解决你的问题,请参考以下文章

10.7校内测试队列滑窗2-sat贪心+栈二分+线段树(noip模拟好题)生日祭!

校内模拟次短路

校内测6.28

NOIP模拟赛-旅行者问题 解题报告

jzoj3423NOIP2013模拟匈牙利Vani和Cl2捉迷藏

NOIp2016 十连测 round1