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\n");
        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\n”,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\n",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;
}
时间: 2024-10-06 14:59:51

9.15模拟赛的相关文章

8.15模拟赛

T1.第K小数[问题描述]有两个正整数数列,元素个数分别为N和M.从两个数列中分别任取一个数相乘,这样一共可以得到N*M个数,询问这N*M个数中第K小数是多少.[输入格式]输入文件名为number.in.输入文件包含三行.第一行为三个正整数N,M和K.第二行为N个正整数,表示第一个数列.第三行为M个正整数,表述第二个数列.[输出格式]输出文件名为number.out.输出文件包含一行,一个正整数表示第K小数.[输入输出样例1 1 ]number.in 2 3 41 22 1 3 number.o

3.15 模拟赛

T1 T2 小R的箱子 T3 绯红之王 题目大意: 已知数列$a$,求$\sum\limits_{i=1}^n {a_i}^k$ 思路: 很久以前讲过的题,调了一年才搞出来 首先设$f_k=\sum\limits_{i=1}^n {a_i}^k$ , $g_k$表示对于所有$C_n^k$种选择的方法,$g_k=$所有方法内各个数相乘的和 例如数列中有四个数$a,b,c,d$ 则 $g_0=1$ $g_1=a+b+c+d$ $g_2=ab+ac+ad+bc+bd+cd$ $g_3=abc+abd+

2017/9/15模拟赛

游戏(game) [问题描述] 小R和小H在玩某个双人联机小游戏,一开始两人所操控的角色各有1点力量值,而在游戏中,每通过一关都会掉落一些力量强化道具.奇怪的是,明明是双人小游戏,每关却都会掉落3个相同的力量强化道具,于是两人决定每关每人先拿一个,剩下一个猜拳决定给谁.一个力量强化道具能使一个角色的力量值变为原来的若干整数倍,同一关卡掉落的道具倍率都相同,而不同的关卡可能不同.小R从攻略上找到了一些会产生特殊效果的力量值组合,他想知道哪些组合是按他们的道具分配方式有可能在通过某关时达成的. [输

10月15日模拟赛题解

10月15日模拟赛题解 A 树 Description 给定一棵 \(n\) 个节点的树,每个节点有两个参数 \(a,~b\),对于每个节点,求子树中参数为 \(b\) 的所有节点的 \(a\) 之和 Limitations \(100\%\) \(1 \leq b \leq n \leq 10^5,~a \leq 1000\) \(60\%\) \(1 \leq b,n\leq 1000\) \(30\%\) \(1 \leq b, n \leq 10\) Solution 对于 \(30\%

8月15日模拟赛小结

今天的模拟赛是三道陈老师的题. 在 10:48 左右已经都能拿到了. 然后我觉得 T3 的蒙特卡洛算法不太稳, 于是调大参数. 本地不开 O2 需要 5s 左右, 开 O2 测需要 2s , 而时限是 3s . 我想着 XSY 也开了 O2 , 所以稳了. 结果比赛结束 T3 全部 TLE ..... 中途还犯了一次A题代码交到B题的错误. ZJT大爷说我从第 2 调到了倒数第 1 , QAQ . 得出结论: ① 很多评测机可能很辣鸡. 所以如果对于随机化算法之类的, 能开大迭代次数的标准是:

【BZOJ】【2741】【FOTILE模拟赛】L

可持久化Trie+分块 神题……Orz zyf & lyd 首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问[某个区间中最大的区间异或和]改变成[某个区间中 max(两个数的异或和)] 要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了:然而我们并不能. 一个常见的折中方案:分块! 这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值. 我们不预处理所有的左端点,我

10.30 NFLS-NOIP模拟赛 解题报告

总结:今天去了NOIP模拟赛,其实是几道USACO的经典的题目,第一题和最后一题都有思路,第二题是我一开始写了个spfa,写了一半中途发现应该是矩阵乘法,然后没做完,然后就没有然后了!第二题的暴力都没码QAQ 现在我来写解题报告了,有点饿了QAQ.. 第一题 题目 1: 架设电话线 [Jeffrey Wang, 2007] 最近,Farmer John的奶牛们越来越不满于牛棚里一塌糊涂的电话服务,于 是,她们要求FJ把那些老旧的电话线换成性能更好的新电话线.新的电话线架设 在已有的N(2 <=

bzoj 2741: 【FOTILE模拟赛】L 分塊+可持久化trie

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1116  Solved: 292[Submit][Status] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y):

【题解】PAT团体程序设计天梯赛 - 模拟赛

由于本人愚笨,最后一题实在无力AC,于是只有前14题的题解Orz 总的来说,这次模拟赛的题目不算难,前14题基本上一眼就有思路,但是某些题写起来确实不太容易,编码复杂度有点高~ L1-1 N个数求和 设计一个分数类,重载加法运算符,注意要约分,用欧几里得算法求个最大公约数即可. 1 #include <cstdio> 2 3 long long abs(long long x) 4 { 5 return x < 0 ? -x : x; 6 } 7 8 long long gcd(long