zoukankan      html  css  js  c++  java
  • 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分 暴力深搜
    /*
        由于走到某个数字的最小操作数只与那个走到它的数字有关,所以问题满足无后效性,问题可以转变为问走到第n+1个位置的最小操作数。
        f[i]表示走到第i个数字的最小操作数,那么可以以它为中心来更新后面位置的最小操作数,答案为f[n+1]
    */
    #include<cstdio>
    const int maxn=1000010;
    int n;
    int s[maxn],f[maxn];
    int main(){
        freopen("sequence.in","r",stdin);
        freopen("sequence.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&s[i]);
            f[i]=maxn;
        }
        int a,b,c;
        f[1]=0,f[n+1]=maxn;
        for(int i=1;i<=n;i++){
            a=i+s[i]+1;
            b=f[i];
            if(a>n+1){
                c=a-n;
                for(int j=n+1;j>i&&f[j]>n-j+b+c;j--)f[j]=n-j+b+c;
            }
            else if(f[a]>b){
                f[a]=b;
                for(int j=a-1;j>i&&f[j]>a-j+b;j--)f[j]=a-j+b;
                for(int j=a+1;j<=n+1&&f[j]>j-a+b;j++)f[j]=j-a+b;
            }
        }
        printf("%d
    ",f[n+1]);
        return 0;
    }
    100分 dp

     

    促销

    【题目描述】

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

    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(记忆化没写成)
    /*
        对于一个给定正实数x,如果x≡0(mod i),那么x≡0(mod x/i)。
        这样一来我们可以将区间放缩,由[1,n]缩小到[1,√n],每次如果x≡0(mod i),SUM+=i+n/i;值得一说的是,区间到达√n的时候,需要进行特判。
    
        如果x≡0(mod √n),那么需要和只需要加一个√n就好了。
    */
    #include<cstdio>
    int a,b,ans;
    int div(int n){
        int i=2,m=1;
        for(;i*i<n;i++)if(n%i==0)m+=i+n/i;
        if(i*i==n)return m+i;
        return m;
    }
    int main (){
        scanf("%d %d",&a,&b);
        for(;a<=b;a++){
            int x=div(a);
            if(x>a&&div(x)==a)ans++;
        }
        printf("%d",ans);
        return 0;
    }
    100分
  • 相关阅读:
    Key-Value Memory Network
    Deep Mask Memory Network with Semantic Dependency and Context Moment for Aspect Level Sentiment Clas
    Deep Memory Network在Aspect Based Sentiment方向上的应用
    Deep Memory Network 深度记忆网络
    Self Attention 自注意力机制
    Attention基本公式及其变种
    *端策略优化算法(PPO)
    Policy Gradient 算法
    一本通 农场派对
    A
  • 原文地址:https://www.cnblogs.com/thmyl/p/7459681.html
Copyright © 2011-2022 走看看