zoukankan      html  css  js  c++  java
  • 9.15模拟赛

    T1 np问题

    题目描述

    LYK喜欢研究一些比较困难的问题,比如np问题。

    这次它又遇到一个棘手的np问题。问题是这个样子的:有两个数n和p,求n的阶乘对p取模后的结果。

    LYK觉得所有np问题都是没有多项式复杂度的算法的,所以它打算求助即将要参加noip的你,帮帮LYK吧!

    输入输出格式

    输入格式:

    输入一行两个整数n,p。

    输出格式:

    输出一行一个整数表示答案。

    输入输出样例

    输入样例#1:
    3 4
    输出样例#1:
    2

    说明

    对于20%的数据:n,p<=5。

    对于40%的数据:n,p<=1000。

    对于60%的数据:n,p<=10000000。

    对于80%的数据:n<=10^18,p<=10000000。

    对于另外20%的数据:n<=10^18,p=1000000007。

    其中大致有50%的数据满足n>=p。

    题解:

    如果n>=p输出0,如果n<=10000000直接跑,如果n<p<=1000000007打表。

    分段打表 每段 10^7。

    第一题煞笔了,%到0才break,直接判断输出0不就行了....50分都没有...Q^Q

    老师还手动证明了快速乘比直接乘慢....my heart is flowing blood

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #ifdef unix
    #define LL "%lld"
    #else
    #define LL "%I64d"
    #endif
    long long n,p,ans=1;
    inline long long read(){
        char ch=getchar();long long x=0,f=1;
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
        return x*f;
    }
    
    long long num[120]={1,682498929,491101308,76479948,723816384,67347853,27368307,625544428,199888908,
    888050723,927880474,281863274,661224977,623534362,970055531,261384175,195888993,66404266,547665832,
    109838563,933245637,724691727,368925948,268838846,136026497,112390913,135498044,217544623,419363534,
    500780548,668123525,128487469,30977140,522049725,309058615,386027524,189239124,148528617,940567523,
    917084264,429277690,996164327,358655417,568392357,780072518,462639908,275105629,909210595,99199382,
    703397904,733333339,97830135,608823837,256141983,141827977,696628828,637939935,811575797,848924691,
    131772368,724464507,272814771,326159309,456152084,903466878,92255682,769795511,373745190,606241871,
    825871994,957939114,435887178,852304035,663307737,375297772,217598709,624148346,671734977,624500515,
    748510389,203191898,423951674,629786193,672850561,814362881,823845496,116667533,256473217,627655552,
    245795606,586445753,172114298,193781724,778983779,83868974,315103615,965785236,492741665,377329025,
    847549272,698611116};
    
    int main(){
        n=read();p=read();
        if(n>=p){
            printf("0
    ");
            return 0;
        }
        if(p==1000000007){
            ans=num[n/10000000];
            for(int i=n/10000000*10000000+1;i<=n;i++)ans=ans*i%p;
            cout<<ans%p<<endl;    
            return 0;
        }
        for(int i=1;i<=n;i++)
         ans=ans*i%p;
        cout<<ans%p<<endl;
        return 0;
    }

    T2

    看程序写结果

    题目描述

    LYK最近在准备NOIP2017的初赛,它最不擅长的就是看程序写结果了,因此它拼命地在练习。

    这次它拿到这样的一个程序:

    Pascal:

    readln(n);
    for i:=1 to n do read(a[i]);
    for i:=1 to n do for j:=1 to n do for k:=1 to n do for l:=1 to n do
      if (a[i]=a[j]) and (a[i]<a[k]) and (a[k]=a[l]) then ans:=(ans+1) mod 1000000007;
    writeln(ans);

    C++:

    pcanf(“%d”,&n);
    for (i=1; i<=n; i++) scanf(“%d”,&a[i]);
    for (i=1; i<=n; i++) for (j=1; j<=n; j++) for (k=1; k<=n; k++) for (l=1; l<=n; l++)
      if (a[i]==a[j] && a[i]<a[k] && a[k]==a[l]) ans=(ans+1)%1000000007;
    printf(“%d
    ”,ans);
    LYK知道了所有输入数据,它想知道这个程序运行下来会输出多少。

    输入输出格式

    输入格式:

     

    第一行一个数n,第二行n个数,表示ai。

     

    输出格式:

     

    一个数表示答案。

     

    输入输出样例

    输入样例#1:
    4
    1 1 3 3
    输出样例#1:
    4

    说明

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

    对于40%的数据n<=200。

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

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

    题解:

    直接把程序搬上去20分。

    正解:首先看第一层和第三层循环,作用是寻找和它一样的数有多少个。我们可以记录一下每个数

    有多少个,在平方就是前两层循环找的方案数,然后用前缀和记录,每个数乘以比它大的个数。

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define maxn 100005
    #define mod 1000000007LL
    using namespace std;
    
    int a[maxn],n,cnt;
    long long num[maxn],sum[maxn],ans;
    
    inline int read(){
        char ch=getchar();int x=0,f=1;
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
        return x*f;
    }
    
    int main(){
        n=read();
        for(int i=1;i<=n;i++)a[i]=read();
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++){
            if(a[i]!=a[i-1])cnt++;
            num[cnt]++;
        }
        for(int i=1;i<=cnt;i++){
            num[i]=(num[i]*num[i])%mod;
            sum[i]=sum[i-1]+num[i];
        }
        for(int i=1;i<cnt;i++){
            ans=(ans+num[i]*(sum[cnt]-sum[i]))%mod;
        }
        cout<<ans<<endl;
        return 0;
    }

    T3 选数字

    题目描述

    LYK找到了一个n*m的矩阵,这个矩阵上都填有一些数字,对于第i行第j列的位置上的数为ai,j。

    由于它AK了noip2016的初赛,最近显得非常无聊,便想到了一个方法自娱自乐一番。它想到的游戏是这样的:每次选择一行或者一列,它得到的快乐值将会是这一行或者一列的数字之和。之后它将该行或者该列上的数字都减去p(之后可能变成负数)。如此,重复k次,它得到的快乐值之和将会是它NOIP2016复赛比赛时的RP值。

    LYK当然想让它的RP值尽可能高,于是它来求助于你。

    输入输出格式

    输入格式:

     

    第一行4个数n,m,k,p。

    接下来n行m列,表示ai,j。

     

    输出格式:

     

    输出一行表示最大RP值。

     

    输入输出样例

    输入样例#1:
    2 2 5 2
    1 3
    2 4
    输出样例#1:
    11

    说明

    总共10组数据。

    对于第1,2组数据n,m,k<=5。

    对于第3组数据k=1。

    对于第4组数据p=0。

    对于第5,6组数据n=1,m,k<=1000。

    对于第7,8组数据n=1,m<=1000,k<=1000000。

    对于所有数据1<=n,m<=1000,k<=1000000,1<=ai,j<=1000,0<=p<=100。

    样例解释

    第一次选择第二列,第二次选择第二行,第三次选择第一行,第四次选择第二行,第五次选择第一行,快乐值为7+4+2+0+-2=11。

    其中均匀分布着50%的数据不同的ai个数<=10,对于另外50%的数据不同的ai个数>=n/10。

    题目大意:每次选矩阵的某一行或者是某一列,得到列或者行的和,然后每个数-p,重复q次。

    题解:40分 特判+暴力鬼畜贪心。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    int n,m,k,p,maxn,x;
    long long ans;
    
    inline int read(){
        int x=0,f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
        return x*f;
    }
    
    struct CC{
        int sum,id;
    }col[1002];
    
    struct RR{
        int sum,id;
    }row[1002];
    
    bool cmpc(CC a,CC b){
        return a.sum>b.sum;
    }
    
    bool cmpr(RR a,RR b){
        return a.sum>b.sum;
    }
    
    int main(){
        freopen("select.in","r",stdin);
        freopen("select.out","w",stdout);
        n=read();m=read();k=read();p=read();
        //n行 m列 k重复次数  减去p
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                x=read();
                row[i].id=i;row[i].sum+=x;
                col[j].id=j;col[j].sum+=x;
                maxn=max(maxn,max(row[i].sum,col[j].sum));
            }
        } 
        
        if(k==1){printf("%d
    ",maxn);return 0;}
        if(p==0){cout<<1LL*k*maxn;return 0;}
        sort(row+1,row+n+1,cmpr);
        sort(col+1,col+m+1,cmpc);
        for(int i=1;i<=k;i++){
            if(row[1].sum>col[1].sum){
                ans+=row[1].sum;
                row[1].sum-=(p*m);
                for(int i=1;i<=m;i++)col[i].sum-=p;
            }else{
                ans+=col[1].sum;
                col[1].sum-=(p*m);
                for(int i=1;i<=n;i++)row[i].sum-=p;
            }
            sort(row+1,row+n+1,cmpr);
            sort(col+1,col+m+1,cmpc);
        }
        cout<<ans<<endl;
        fclose(stdin);
        fclose(stdout);
        return 0;
    }

    正解:贪心+枚举

    发现每次取行或者是列都是独立的。预处理出行的前k大值,列的前k大值。

    枚举行取多少个,列就是k-行的个数,最后再减去没有减的p。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int n,m,k,p;
    long long ans;
    long long  row[1010],col[1010],sum1[1010000],sum2[1010000];
    inline int read(){
        char ch=getchar();int x=0,f=1;
        for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x*f; 
    }
    
    int main(){
        n=read();m=read();k=read();p=read();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int x;x=read();    
                row[i]+=x;col[j]+=x;    
            }
        }
        make_heap(row+1,row+n+1);
        make_heap(col+1,col+m+1);
        for(int i=1;i<=k;i++){
            sum1[i]=sum1[i-1]+row[1];
            pop_heap(row+1,row+n+1);
            row[n]-=m*p;
            push_heap(row+1,row+n+1);
            sum2[i]=sum2[i-1]+col[1];
            pop_heap(col+1,col+m+1);
            col[m]-=n*p;
            push_heap(col+1,col+m+1);
        }
        ans=1LL*-100000000*1000000000;
        for(int i=0;i<=k;i++)ans=max(ans,sum1[i]+sum2[k-i]-1LL*i*(k-i)*p);
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    python基础一 day41 IO模型 非阻塞IO
    python基础一 day41 协程
    python基础一 day41 复习
    python基础一 day40 条件 定时器 队列 线程池
    python基础一 day40 线程锁 信号量 事件
    第三章
    第二章
    第一章
    计算机基础知识
    scrapy安装方法
  • 原文地址:https://www.cnblogs.com/zzyh/p/7528542.html
Copyright © 2011-2022 走看看