zoukankan      html  css  js  c++  java
  • 模拟赛 10-25上午考试记

    10-25上午考试记

    NP(np)

    Time Limit:1000ms Memory Limit:64MB
    题目描述
    LYK 喜欢研究一些比较困难的问题,比如 np 问题。
    这次它又遇到一个棘手的 np 问题。问题是这个样子的:有两个数 n 和 p,求 n 的阶乘
    对 p 取模后的结果。
    LYK 觉得所有 np 问题都是没有多项式复杂度的算法的,所以它打算求助即将要参加 noip
    的你,帮帮 LYK 吧!

    打表发现如果n>=p,答案就是0。

    所以把n的范围缩小到1e7。但是有p=1e9+7。

    分段打表就可以。 段长我设的1000000。

    code:

    #include <iostream>
    #include <cstdio>
    
    #define int long long
    
    using namespace std;
    
    inline int read(){
    	int sum=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    	return sum*f;
    }
    
    int n,p;
    
    int a[117]={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};
    /*
    时间: 1e7 空间:1e2 
    */
    signed main(){
    	freopen("np.in","r",stdin);
    	freopen("np.out","w",stdout);
    	
    	n=read(); p=read();
    	if(n>=p){
    		puts("0");
    		return 0;
    	}
    	if(p==1000000007){
    		int zmj=n/10000000;
    		int ans=a[zmj];
    		for(int i=zmj*10000000+1;i<=n;i++){
    			ans=ans*i%p;
    		}
    		printf("%lld
    ",ans%p);
    		return 0;
    	}
    	int ans=1;
    	for(int i=1;i<=n;i++){
    		ans=ans*i%p;
    	}
    	printf("%lld
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    看程序写结果(program)

    Time Limit:1000ms Memory Limit:64MB
    题目描述
    LYK 最近在准备 NOIP2017 的初赛,它最不擅长的就是看程序写结果了,因此它拼命地
    在练习。
    这次它拿到这样的一个程序:
    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[i]<a[k] && a[k]==a[l]) ans=(ans+1)%1000000007;
    printf(“%d ”,ans);

    首先把这段代码复制就有20分。

    优化。

    把数学式子化简。

    [ans=sum_{i=1}^nsum_{j=1}^nsum_{k=1}^nsum_{l=1}^n[a[i]== a[j]  and  a[i]<a[k]  and  a[k]==a[l]]\=sum_{i=1}^nsum_{j=i+1}^n[t[a[i]]*t[a[j]]]\=sum_{i=1}^nt[a[i]]*sum_{j=i+1}^nt[a[j]] ]

    考虑到要开桶,所以去重离散化,一堆令人窒息的操作。

    code:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    
    #define int long long
    
    using namespace std;
    
    inline int read(){
    	int sum=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    	return sum*f;
    }
    
    const int mod=1000000007;
    
    const int wx=500017;
    
    int js[wx];
    int a[wx],b[wx];
    int t[wx];
    int nxt[wx],pre[wx];
    
    int n;
    /*
    时间: O(nlogn) 空间: 500000*6 22MB
    */
    signed main(){
    	freopen("program.in","r",stdin);
    	freopen("program.out","w",stdout);
    	
    	n=read(); 
    	for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i];
    	sort(b+1,b+1+n);
    	int zmj=unique(b+1,b+1+n)-b;
    	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+zmj,a[i])-b;
    	for(int i=1;i<=n;i++)t[a[i]]++;
    	sort(a+1,a+1+n);
    	int ans=0;int last=0;
    	for(int i=1;i<=n;i++){
    		nxt[i]=n+1;
    		if(a[i]!=a[i-1]){
    			nxt[last]=i;
    			last=i;
    		}
    	}
    	last=n+1;
    	for(int i=n;i>=1;i--){
    		if(a[i]!=a[i+1]){
    			pre[last]=i; 
    			last=i;
    		}
    	}
    	js[a[n]]=0; last=n;
    	for(int i=pre[n];i>=1;i=pre[i]){
    		js[a[i]]=js[a[last]]+(t[a[last]]*t[a[last]]%mod);
    		js[a[i]]%=mod;
    		last=i;
    	}
    	for(int i=1;i<=n;i=nxt[i]){
    		ans=(ans+((t[a[i]]*t[a[i]])%mod*js[a[i]])%mod);
    		ans%=mod;
    	}
    	printf("%lld
    ",ans%mod);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    选数字 (select)

    Time Limit:3000ms Memory Limit:64MB
    题目描述
    LYK 找到了一个 n*m 的矩阵,这个矩阵上都填有一些数字,对于第 i 行第 j 列的位置上
    的数为 ai,j。
    由于它 AK 了 noip2016 的初赛,最近显得非常无聊,便想到了一个方法自娱自乐一番。
    它想到的游戏是这样的:每次选择一行或者一列,它得到的快乐值将会是这一行或者一列的
    数字之和。之后它将该行或者该列上的数字都减去 p(之后可能变成负数)。如此,重复 k
    次,它得到的快乐值之和将会是它 NOIP2016 复赛比赛时的 RP 值。
    LYK 当然想让它的 RP 值尽可能高,于是它来求助于你。

    先无脑暴力。

    暴力之后感觉很无力啊。。。

    那就贪心吧,最恶心的是行和列混在一起,明显有后效性啊。

    那就强行把行和列拆开,分别处理出取i个行或j的最大答案。

    还需要合并行和列的情况,那就枚举一个。

    可以得到式子:

    [ans=max(ans,x[i]+y[k-i]-i*(k-i)*q) ]

    为什么要减呢?因为我们处理出x和y两个数组是是互相独立的,也就是我们不考虑另一种情况。

    所以这时的(i)行,(k-i)列都少减了对方所带来的一部分,那么就减去就可以了。

    还有一个坑点是ans要附成极小值,中间变量还会炸int。

    果然傻人有傻福,我直接(int  ans=-1e17)加上(define  int  long  long)就无脑过掉了这道题。

    code:

    #include <iostream>
    #include <cstdio>
    #include <queue>
    
    #define int long long
    
    using namespace std;
    
    inline int read(){
    	int sum=0,f=1; char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0'; ch=getchar();}
    	return sum*f;
    }
    
    const int wx=1500;
    
    priority_queue<int > zmj1;
    priority_queue<int > zmj2;
    
    int mp[wx][wx];
    int x[wx],y[wx];
    int ansx[1000017],ansy[1000017];
    int n,m,k,p,ans=-1e17;
    
    void work1(){
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			mp[i][j]=read();
    			x[i]+=mp[i][j];
    			y[j]+=mp[i][j];
    		}
    	}
    	int maxn=-0x3f3f3f3f;
    	for(int i=1;i<=n;i++)maxn=max(maxn,x[i]);
    	for(int i=1;i<=m;i++)maxn=max(maxn,y[i]);
    	if(k==1)printf("%lld
    ",maxn);
    	else if(p==0)printf("%lld
    ",maxn*k);
    	return ;
    }
    
    
    void dfs(int step,int tot){
    	if(step==k+1){
    		ans=max(ans,tot);
    		return ;
    	}
    	for(int i=1;i<=n;i++){
    		int tmp=0;
    		for(int j=1;j<=m;j++){
    			tmp+=mp[i][j];
    			mp[i][j]-=p;
    		}
    		dfs(step+1,tot+tmp);
    		for(int j=1;j<=m;j++)
    			mp[i][j]+=p;
    	}
    	for(int i=1;i<=m;i++){
    		int tmp=0;
    		for(int j=1;j<=n;j++){
    			tmp+=mp[j][i];
    			mp[j][i]-=p;
    		}
    		dfs(step+1,tot+tmp);
    		for(int j=1;j<=n;j++){
    			mp[j][i]+=p;
    		}
    	}
    }
    
    void work2(){
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			mp[i][j]=read();
    		dfs(1,0);
    	printf("%lld
    ",ans);
    } 
    
    void work3(){
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			mp[i][j]=read();
    			x[i]+=mp[i][j];
    			y[j]+=mp[i][j];
    		}
    	}
    	for(int i=1;i<=n;i++)zmj1.push(x[i]);
    	for(int i=1;i<=m;i++)zmj2.push(y[i]);
    	for(int i=1;i<=k;i++){
    		int tmp=zmj1.top(); zmj1.pop();
    		ansx[i]=ansx[i-1]+tmp;
    		zmj1.push(tmp-p*m);
    		tmp=zmj2.top(); zmj2.pop();
    		ansy[i]=ansy[i-1]+tmp;
    		zmj2.push(tmp-p*n);
    	}
    	for(int i=0;i<=k;i++){
    		ans=max(ans,ansx[i]+ansy[k-i]-i*(k-i)*p);
    	}
    	printf("%lld
    ",ans);
    	return;
    }
    /*
    时间:O(ologn) 空间: 4500000 32MB 
    */
    signed main(){
    	freopen("select.in","r",stdin);
    	freopen("select.out","w",stdout);
    	
    	n=read(); m=read(); k=read(); p=read();
    	if(k==1||p==0){
    		work1();
    		fclose(stdin);
    		fclose(stdout);
    		return 0;
    	}
    	else if(n<=5&&m<=5&&k<=5){
    		work2();
    		fclose(stdin);
    		fclose(stdout);
    		return 0;
    	}
    	else{
    		work3();
    		fclose(stdin);
    		fclose(stdout);
    		return 0;
    	}
    	
    }
    

    总结:

    T1考的打表。主要是分段打表看谁用的好吧。。

    T2细节蛮多,但是不难。

    T3思维题,这几天的考试都告诉我T3不要上来就想比较难的算法,可能那不是正解,要好好思考一下一些基础算法是否适用于这道题,可能基础算法才是正解。

    垃圾小呆上午AK,静心等待下午爆炸。。

  • 相关阅读:
    [Vijos] 天才的记忆
    [Vijos] 河蟹王国
    [Vijos] SuperBrother打鼹鼠
    [Vijos] 弱弱的战壕
    [洛谷P3792] 由乃与大母神原型和偶像崇拜
    【模板】乘法逆元
    [USACO13NOV]空荡荡的摊位Empty Stalls
    [USACO08OPEN]牛的车Cow Cars
    [SCOI2005]扫雷
    [USACO16OPEN]关闭农场Closing the Farm_Silver
  • 原文地址:https://www.cnblogs.com/wangxiaodai/p/9848922.html
Copyright © 2011-2022 走看看