2017.9.15 模拟考试

51 篇文章 0 订阅
45 篇文章 0 订阅

NP(np)
Time Limit:1000ms Memory Limit:64MB
题目描述
LYK喜欢研究一些比较困难的问题,比如np问题。
这次它又遇到一个棘手的np问题。问题是这个样子的:有两个数n和p,求n的阶乘对p取模后的结果。
LYK觉得所有np问题都是没有多项式复杂度的算法的,所以它打算求助即将要参加noip的你,帮帮LYK吧!
输入格式(np.in)
输入一行两个整数n,p。
输出格式(np.out)
输出一行一个整数表示答案。
输入样例
3 4
输出样例
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。
我的代码:

#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
#define LL long long
LL n,p;
void solve(){
    LL ans=1;
    for(register LL i=2;i<=n;++i) ans=(ans*i)%p;
    printf("%I64d\n",ans);
}

int Main(){
    freopen("np.in","r",stdin);
    freopen("np.out","w",stdout);
    scanf("%I64d%I64d",&n,&p);
    if(n>=p) { printf("0\n"); return 0; }
    else solve();
    fclose(stdin);fclose(stdout);
    return 0;
}
int Aptal_is_My_son=Main();
int main(int argc,char *argv[]){ ; }
//正解:分块打表  我没打90#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;
#define LL long long
LL n,p;
LL a[110]={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(){
    freopen("np.in","r",stdin);
    freopen("np.out","w",stdout);
    scanf("%I64d%I64d",&n,&p);
    if(n>=p) { printf("0\n"); return 0; }
    if(p==1000000007){
        LL now=n/10000000;
        LL ans=a[now];
        for(LL i=now*10000000+1;i<=n;++i) ans=ans*i%p;
        printf("%I64d\n",ans%p);
        return 0;
    }
    LL ans=1;
    for(int i=1;i<=n;++i) ans=ans*i%p;
    printf("%I64d\n",ans%p);
    fclose(stdin);fclose(stdout);
    return 0;
}

看程序写结果(program)
Time Limit:1000ms Memory Limit:64MB

题目描述
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\n”,ans);
LYK知道了所有输入数据,它想知道这个程序运行下来会输出多少。
输入格式(program.in)
第一行一个数n,第二行n个数,表示ai。
输出格式(program.out)
一个数表示答案。
输入样例
4
1 1 3 3
输出样例
4
数据范围
对于20%的数据n<=50。
对于40%的数据n<=200。
对于60%的数据n<=2000。
对于100%的数据n<=100000,1<=ai<=1000000000。
其中均匀分布着50%的数据不同的ai个数<=10,对于另外50%的数据不同的ai个数>=n/10。

题目本意:求满足这种情况的状态数a[i]==a[j]

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
#define MAXN 100000
int a[MAXN],n,ans;
map<int,int> Mp;
#define Mod 1000000007

int Main(){
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    scanf("%d",&n);
    register int k,i;
    for (i=1; i<=n; i++) scanf("%d",&a[i]),++Mp[a[i]];
    for (i=1; i<=n; i++) for (k=1; k<=n; k++)
        if ( a[i]<a[k] ) ans=(ans + Mp[a[k]] * Mp[a[i]])%1000000007; 
    printf("%d\n",ans);
    fclose(stdin);fclose(stdout);
    return 0;
}
int Aptal_is_My_son=Main();
int main(int argc,char *argv[ ]){ ; }

选数字 (select)
Time Limit:3000ms Memory Limit:64MB

题目描述
LYK找到了一个n*m的矩阵,这个矩阵上都填有一些数字,对于第i行第j列的位置上的数为ai,j。
由于它AK了noip2016的初赛,最近显得非常无聊,便想到了一个方法自娱自乐一番。它想到的游戏是这样的:每次选择一行或者一列,它得到的快乐值将会是这一行或者一列的数字之和。之后它将该行或者该列上的数字都减去p(之后可能变成负数)。如此,重复k次,它得到的快乐值之和将会是它NOIP2016复赛比赛时的RP值。
LYK当然想让它的RP值尽可能高,于是它来求助于你。
输入格式(select.in)
第一行4个数n,m,k,p。
接下来n行m列,表示ai,j。
输出格式(select.out)
输出一行表示最大RP值。
输入样例
2 2 5 2
1 3
2 4
输出样例
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。

考场心血来潮,码了一个半小时的字,期望六七十分,实测40分。。
这里写图片描述

明显是贪心思路,然而贪心的思路是错的。。
GG

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN 1005
#define LL long long 
#define INF 0x5fffffff
LL sum_hang[MAXN],sum_lie[MAXN];
int n,m,k,p;
LL ans=0,ans1,ans2;
inline void read(int &x){
    x=0; int f=1; char c=getchar();
    while(c>'9'||c<'0'){ if(c=='-') f=-1; c=getchar(); }
    while(c>='0'&&c<='9'){  x=x*10+c-'0'; c=getchar(); } x*=f;
}
struct SegMent_Tree{ int l,r,maxx,lazy,pos; }tre_hang[MAXN<<2],tre_lie[MAXN<<2];
#define hang tre_hang
#define lie tre_lie

inline void UpDate_Hang(int u){
    hang[u].maxx=max(hang[u<<1].maxx,hang[u<<1|1].maxx);
    if(hang[u].maxx==hang[u<<1].maxx) hang[u].pos=hang[u<<1].pos;
    else hang[u].pos=hang[u<<1|1].pos;
}
inline void UpDate_Lie(int u){
    lie[u].maxx=max(lie[u<<1].maxx,lie[u<<1|1].maxx);
    if(lie[u].maxx==lie[u<<1].maxx) lie[u].pos=lie[u<<1].pos;
    else lie[u].pos=lie[u<<1|1].pos;
}

void Build_Tre_Hang(int u,int l,int r){
    hang[u].l=l,hang[u].r=r,hang[u].maxx=-INF,hang[u].lazy=0;
    if(l==r){ hang[u].maxx=sum_hang[l];hang[u].pos=l; return ; }
    int Mid=l+r>>1;
    Build_Tre_Hang(u<<1,l,Mid);
    Build_Tre_Hang(u<<1|1,Mid+1,r);
    UpDate_Hang(u);
}
void Build_Tre_Lie(int u,int l,int r){
    lie[u].l=l,lie[u].r=r,lie[u].maxx=-INF,lie[u].lazy=0;
    if(l==r){ lie[u].maxx=sum_lie[l];lie[u].pos=l; return ; }
    int Mid=l+r>>1;
    Build_Tre_Lie(u<<1,l,Mid);
    Build_Tre_Lie(u<<1|1,Mid+1,r);
    UpDate_Lie(u);
}

void Push_Down_Hang(int u){
    hang[u<<1].lazy+=hang[u].lazy;
    hang[u<<1|1].lazy+=hang[u].lazy;
    hang[u<<1].maxx-=hang[u<<1].lazy,hang[u<<1|1].maxx-=hang[u<<1|1].lazy;
    hang[u].lazy=0;
}

void Push_Down_Lie(int u){
    lie[u<<1].lazy+=lie[u].lazy;
    lie[u<<1|1].lazy+=lie[u].lazy;
    lie[u<<1].maxx-=lie[u<<1].lazy,lie[u<<1|1].maxx-=lie[u<<1|1].lazy;
    lie[u].lazy=0;
}
struct Ans{ int pos,maxx; };
Ans Query_Hang(int u,int l,int r){
    if(l<=hang[u].l&&hang[u].r<=r){
        Ans ret;
        ret.pos = hang[u].pos;
        ret.maxx = hang[u].maxx;
        return ret;
    }
    int Mid=hang[u].l+hang[u].r>>1;
    if(hang[u].lazy!=0) Push_Down_Hang(u);
    if(l>Mid) return Query_Hang(u<<1|1,l,r);
    else if(r<=Mid) return Query_Hang(u<<1,l,r);
    else {
        Ans retl=Query_Hang(u<<1,l,Mid);
        Ans retr=Query_Hang(u<<1|1,Mid+1,r);
        if(retl.maxx>retr.maxx) return retl;
        else return retr;
    }
}
Ans Query_Lie(int u,int l,int r){
    if(l<=lie[u].l&&lie[u].r<=r){
        Ans ret;
        ret.pos = lie[u].pos;
        ret.maxx = lie[u].maxx;
        return ret;
    }
    int Mid=lie[u].l+lie[u].r>>1;
    if(lie[u].lazy!=0) Push_Down_Lie(u);
    if(l>Mid) return Query_Lie(u<<1|1,l,r);
    else if(r<=Mid) return Query_Lie(u<<1,l,r);
    else {
        Ans retl=Query_Lie(u<<1,l,Mid);
        Ans retr=Query_Lie(u<<1|1,Mid+1,r);
        if(retl.maxx>retr.maxx) return retl;
        else return retr;
    }
}

void Change_Hang(int u,int pos){
    if(hang[u].l==hang[u].r){ hang[u].maxx-=p*m; return ; }
    int Mid=hang[u].l+hang[u].r>>1;
    if(hang[u].lazy!=0) Push_Down_Hang(u);
    if(pos<=Mid) Change_Hang(u<<1,pos);
    else if(pos>Mid) Change_Hang(u<<1|1,pos);
    UpDate_Hang(u);
}
void Change_Lie(int u,int pos){
    if(lie[u].l==lie[u].r){ lie[u].maxx-=p*n; return ; }
    int Mid=lie[u].l+lie[u].r>>1;
    if(lie[u].lazy!=0) Push_Down_Lie(u);
    if(pos<=Mid) Change_Lie(u<<1,pos);
    else if(pos>Mid) Change_Lie(u<<1|1,pos);
    UpDate_Lie(u);
}

void Modify_Hang(int u,int l,int r){
    if(l<=hang[u].l&&hang[u].r<=r){
        hang[u].maxx-=p;
        hang[u].lazy+=p;
        return ;
    }
    if(hang[u].lazy!=0) Push_Down_Hang(u);
    int Mid=hang[u].l+hang[u].r>>1;
    if(r<=Mid) Modify_Hang(u<<1,l,r);
    else if(l>Mid) Modify_Hang(u<<1|1,l,r);
    else {
        Modify_Hang(u<<1,l,Mid);
        Modify_Hang(u<<1|1,Mid+1,r);
    }
    UpDate_Hang(u);
}
void Modify_Lie(int u,int l,int r){
    if(l<=lie[u].l&&lie[u].r<=r){
        lie[u].maxx-=p;
        lie[u].lazy+=p;
        return ;
    }
    if(lie[u].lazy!=0) Push_Down_Lie(u);
    int Mid=lie[u].l+lie[u].r>>1;
    if(r<=Mid) Modify_Lie(u<<1,l,r);
    else if(l>Mid) Modify_Lie(u<<1|1,l,r);
    else {
        Modify_Lie(u<<1,l,Mid);
        Modify_Lie(u<<1|1,Mid+1,r);
    }
    UpDate_Lie(u);
}

void xolve(){
    LL ans=-INF;
    for(int i=1;i<=n;++i) ans=max(ans,sum_hang[i]);
    for(int i=1;i<=m;++i) ans=max(ans,sum_lie[i]);
    cout<<ans*k;
}
int main(){
    freopen("select.in","r",stdin);
    freopen("select.out","w",stdout);
    read(n),read(m),read(k),read(p);
    register int i,j; int x;
    for (i=1; i<=n; ++i)
        for (j=1; j<=m; ++j) read(x),sum_hang[i]+=x,sum_lie[j]+=x;
    if(p==0){ xolve(); return 0; }
    Build_Tre_Hang(1,1,n);
    Build_Tre_Lie(1,1,m);

    while(k--){
        Ans Max_Hang=Query_Hang(1,1,n);
        Ans Max_Lie=Query_Lie(1,1,m);
        if(Max_Hang.maxx>Max_Lie.maxx){//抽 行
            ans+=Max_Hang.maxx;
            Change_Hang(1,Max_Hang.pos);
            Modify_Lie(1,1,m);
        }
        else {//抽 列
            ans+=Max_Lie.maxx;
            Change_Lie(1,Max_Lie.pos);
            Modify_Hang(1,1,n);
        }
    }
    cout<<ans;
    fclose(stdin);fclose(stdout);
    return 0;
}

正解:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<queue>
using namespace std;
#define MAXN 1000005
#define MAXM 1005
#define LL long long
LL sum_hang[MAXM],sum_lie[MAXM],ans=-1e18,sum[MAXN],sum_[MAXN];
LL n,m,k,x,p;
priority_queue<LL,vector<LL> >q;
inline void read(LL &x){
    x=0; int f=1; char c=getchar();
    while(c>'9'||c<'0'){ if(c=='-') f=-1; c=getchar(); }
    while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;
}

void xolve(){
    register int i;register LL xx;
    for( i=1; i<=m; ++i) q.push(sum_lie[i]);
    for( i=1; i<=k; ++i) xx=q.top(),q.pop(),sum_[i]=sum_[i-1]+xx,q.push(xx-n*p);
    while(!q.empty()) q.pop();
    for( i=1; i<=n; ++i) q.push(sum_hang[i]);
    for( i=1; i<=k; ++i) xx=q.top(),q.pop(),sum[i]=sum[i-1]+xx,q.push(xx-m*p);
    for( i=0; i<=k; ++i)
        ans=max(ans,sum[i]+sum_[k-i]-i*(k-i)*p);
    cout<<ans;
}

int Main(){
    freopen("select.in","r",stdin);
    freopen("select.out","w",stdout);
    read(n),read(m),read(k),read(p);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) read(x),sum_hang[i]+=x,sum_lie[j]+=x;
    xolve();
    return 0;
}
int Aptal_is_My_Son=Main();
int main(int argc,char *argv[]){ ; }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值