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

    NP(np)

    Description

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

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

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

    Input

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

    Output

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

    数据范围

    对于 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 geq p)的时候,直接输出(0)

    此时,求解(n)的阶乘的时候会乘上一个(p)

    则代表(n=k imes p)

    然后呢,其他部分的分怎么得?

    分段打表!

    我们打出(10^7)(10^9)部分的阶乘(%1000000007)的值.

    然后遇到(p=1000000007)的情况的时候,我们可以直接跳到这一倍数位置.后面部分暴力扩展即可.

    复杂度(O(能够))

    还玩了半天(python) ~w~

    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    #include<cctype>
    #define int long long 
    #define R register
    using namespace std;
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    int n,p,res=1;
    const int fac[]=
    {
    	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
    };
    signed main()
    {
    	freopen("np.in","r",stdin);
    	freopen("np.out","w",stdout);
    	in(n),in(p);
    	if(n>=p){puts("0");return 0;}
    	if(p==1000000007)
    	{
    		int now=n/10000000;
    		int res=fac[now];
    		for(R int i=now*10000000+1;i<=n;res*=i,res%=p,i++);
    		printf("%lld",(res<0)?(res+p)%p:res%p);
    		return 0;
    	}
    	for(R int i=1;i<=n;res*=i,res%=p,i++);
    	printf("%lld",(res<0)?(res+p)%p:res%p);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    看程序写结果(program)

    Description

    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 知道了所有输入数据, 它想知道这个程序运行下来会输出多少。

    Input

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

    Output

    一个数表示答案。

    数据范围

    数据范围

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

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

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

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

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

    这题得分最简单了把上面代码粘下来都有40pts

    首先你需要离散化.这个看不出来就不怪我了啊

    很容易发现,

    这题要找满足这个条件的东西数量.

    [a[i]==a[j] &&a[i]<a[k] &&a[k]==a[l] ]

    但是你看它枚举的顺序,先别在乎(n^4)

    如果(i==j)依旧成立.即一个数可以和自己组合.

    同时又可以和已经组合过的数组合.

    然后如果有(n)个数的话,两两组合有多少个方案?建议手玩

    (n imes (n-1) + n)

    (+n)即自己和自己组合的方案.

    我竟然没看出来是(n^2),然后直接写了这个式子.

    代码还取了很多模,可丑了

    显然现在的答案就是

    [sum_{i=1}^{cnt}num_i^2 imes sum_{j=i+1}^{cnt}num_j^2 ]

    代码中并不是这样写的.忘了化简式子但是是一样的.

    然后我们可以维护一个后缀和,达到(O(n))求解.

    总复杂度(O(nlogn))

    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    #include<cctype>
    #define N 100008
    #define ll long long
    #define mod 1000000007
    #define R register
    using namespace std;
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    int n,a[N],b[N];
    int tong[N],mx,cnt=1;
    ll ans,sum[N];
    int main()
    {
    	freopen("program.in","r",stdin);
    	freopen("program.out","w",stdout);
    	in(n);
    	for(R int i=1;i<=n;i++)
    		in(a[i]),b[i]=a[i];
    	sort(b+1,b+n+1);
    	for(R int i=2;i<=n;i++)
    		if(b[i]!=b[cnt])b[++cnt]=b[i];
    	for(R int i=1;i<=n;i++)
    	{
    		a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
    		(tong[a[i]]+=1)%=mod;
    	}
    	for(R int i=cnt;i>=1;i--)
    		sum[i]=(sum[i+1]%mod+(((tong[i]%mod)*((tong[i]-1)%mod)%mod)*1LL+(tong[i]%mod)*1LL))%mod;
    	for(R int i=1;i<cnt;i++)
    	{
    		R ll tmp=(((tong[i]%mod)*((tong[i]-1)%mod)*1LL)+tong[i])*1LL;
    		(ans+=tmp*sum[i+1])%=mod;
    	}
    	printf("%lld",(ans<0) ? (ans+mod)%mod:ans%mod);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    选数字(select)

    Description

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

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

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

    Input

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

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

    Output

    输出一行表示最大 RP 值

    正解贪心.

    开两个堆分别维护

    1. (ansx[i])代表在(n)行中选择最大值(i)次的答案.
    2. (ansy[i])代表在(m)列中选择最大值(i)次的答案.

    然后枚举选(i)次行,那么我们就知道选(k-i)次列.

    但是我们重复减去了一些东西,再加上就好了,应该不是很难理解.就不多BB了

    注意极小值一定要够小!!!

    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    #include<cctype>
    #define int long long 
    #define R register
    using namespace std;
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    int n,m,k,p;
    int mx=-2147483644666666LL;
    int xx[1008],yy[1008];
    priority_queue<int>q;
    priority_queue<int>Q;
    int ansx[1000008],ansy[1000008],ans;
    inline int get()
    {
    	R int res=-2147483644666666LL,pos,flg;
    	for(R int i=1;i<=n;i++)
    		if(xx[i]>res)res=xx[i]*1LL,flg=1,pos=i;
    	for(R int j=1;j<=m;j++)
    		if(yy[j]>res)res=yy[j]*1LL,flg=2,pos=j;
    	if(flg==1)
    	{
    		for(R int i=1;i<=m;i++)
    			yy[i]-=p;
    		xx[pos]-=m*p;
    	}
    	if(flg==2)
    	{ 
    		for(R int i=1;i<=n;i++)
    			xx[i]-=p;
    		yy[pos]-=n*p;
    	}
    	return res;
    }
    signed main()
    {
    	freopen("select.in","r",stdin);
    	freopen("select.out","w",stdout);
    	
    	in(n),in(m),in(k),in(p);
    	
    	if(n<=5 and m<=5 and k<=5)
    	{
    		for(R int i=1;i<=n;i++)
    			for(R int j=1,x;j<=m;j++)
    				in(x),xx[i]+=x,yy[j]+=x;
    		for(R int i=1;i<=k;i++)ans+=get();
    		printf("%lld",ans);
    		return 0;
    	}//20pts;
    	
    	
    	if(p==0 or k==1)
    	{
    		for(R int i=1;i<=n;i++)
    			for(R int j=1,x;j<=m;j++)
    				in(x),xx[i]+=x,yy[j]+=x;
    		for(R int i=1;i<=n;i++)mx=max(1LL*xx[i],mx);
    		for(R int i=1;i<=m;i++)mx=max(1LL*yy[i],mx);		
    		printf("%lld",mx*(k*1LL));
    		return 0;
    	}//20pts;
    	
    	
    	for(R int i=1;i<=n;i++)
    		for(R int j=1,x;j<=m;j++)
    			in(x),xx[i]+=x,yy[j]+=x;
    	for(R int i=1;i<=n;i++)q.push(1LL*xx[i]);
    	for(R int i=1;i<=m;i++)Q.push(1LL*yy[i]);
    	for(R int i=1;i<=k;i++)
    	{
    		R int x=q.top();
    		q.pop();
    		ansx[i]=ansx[i-1]+x;
    		q.push(x-p*m);
    		
    		R int y=Q.top();
    		Q.pop();
    		ansy[i]=ansy[i-1]+y;
    		Q.push(y-p*n);
    	}
    	ans=-2147483644666666LL;
    	for(int i=0;i<=k;i++)
    		ans=max(ans,ansx[i]+ansy[k-i]-i*(k-i)*p);
    	printf("%lld",ans);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    c++继承与多态
    逻辑运算符
    页面分栏布局
    js中的三大特殊数据:undefined,null,NaN
    逻辑分支中if小括号中的隐式转换
    最小高度的兼容方法
    js数据类型的转换
    ognl.OgnlException: target is null for setProperty(null, "goodsSize", [Ljava.lang.String;@c3bb5。
    解决拦截器的对于参数传递无效问题
    引用外部js乱码问题
  • 原文地址:https://www.cnblogs.com/-guz/p/9848827.html
Copyright © 2011-2022 走看看