zoukankan      html  css  js  c++  java
  • 2020.07.15【NOIP提高组】模拟

    2020.07.15比赛总结

    最大配对

    题目大意:给出(2)个序列(A={a[1],a[2],…,a[n]},B={b[1],b[2],…,b[n]}),从(A、B)中各选出k个元素进行一一配对(可以不按照原来在序列中的顺序),并使得所有配对元素差的绝对值之和最大。例如各选出了(a[p[1]],a[p[2]],……,a[p[k]])(b[q[1]],b[q[2]],……,b[q[k]]),其中(p)序列中的元素两两不相同,(q)序列中的元素两两不相同,那么答案为(|a[p[1]]-b[q[1]]|+|a[p[2]]-b[q[2]]|+……+|a[p[k]]-b[q[k]]|),现在任务也就是最大化这个答案。

    这题非常的简单,只要你会快排,你就能立马想出来,用最大减最小。

    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    int a[100005],b[100005],n,k;
    
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for (int i=1;i<=n;i++)scanf("%d",&a[i]);
    	for (int i=1;i<=n;i++)scanf("%d",&b[i]);
    	sort(a+1,a+1+n);
    	sort(b+1,b+1+n);
    	int l1=1,r1=n,l2=1,r2=n;
    	long long ans=0;
    	for (int i=1;i<=k;i++)
    	{
    		if (abs(a[l1]-b[r2])>abs(a[r1]-b[l2]))
    		{
    			ans+=(long long)abs(a[l1]-b[r2]);
    			r2--;
    			l1++;
    		}
    		else
    		{
    			ans+=(long long)abs(a[r1]-b[l2]);
    			r1--;
    			l2++;
    		}
    	}
    	printf("%lld
    ",ans);
    }
    

    旅行

    题目大意:教主要带领一群Orzer到一个雄奇地方勘察资源。这个地方可以用一个n×m的矩阵A[i, j]来描述,而教主所在的位置则是位于矩阵的第1行第1列。矩阵的每一个元素A[i, j]均为一个不超过n×m的正整数,描述了位于这个位置资源的类型为第A[i, j]类。教主准备选择一个子矩阵作为勘察的范围,矩阵的左上角即为教主所在的(1, 1)。若某类资源k在教主勘察的范围内恰好出现一次。或者说若教主选择了(x, y)即第x行第y列作为子矩阵的右下角,那么在这个子矩阵中只有一个A[i, j](1≤i≤x,1≤j≤y)满足A[i, j]=k,那么第k类资源则被教主认为是稀有资源。
      现在问题是,对于所有的(x, y),询问若(x, y)作为子矩阵的右下角,会有多少类不同的资源被教主认为是稀有资源。
     为了照顾Vijos脑残的输出问题,设B[i, j]表示仅包含前i行与前j列的子矩阵有多少个数字恰好出现一次,那么你所要输出所有B[i, j]之和mod 19900907。

    正解DP
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    using namespace std;
    int n,a[5000],b[5000],f[5000][3];
    
    int main()
    {
    	scanf("%d",&n);
    	scanf("%d",&a[1]);
    	for (int i=2;i<=n;i++) scanf("%d",&a[i]),b[i]=b[i-1]+abs(a[i]-a[i-1]);
    	a[n+1]=a[n];
    	memset(f,120,sizeof(f));
    	f[n][0]=f[n][1]=0;
    	for (int i=n-1;i>=1;i--)
    	{
    		f[i][0]=min(f[i+1][0]+abs(a[i]-a[i+1]),f[i+1][1]+abs(a[i]-a[i+2]));
    		for (int j=i+1;j<n;j++)
    			f[i][1]=min(f[i][1],min(f[j+1][0]+abs(a[i]-a[j+1]),f[j+1][1]+abs(a[i]-a[j+2]))+abs(a[i]-a[j])+b[j]-b[i+1]);
    		f[i][1]=min(f[i][1],b[n]-b[i+1]+abs(a[i]-a[n]));
    	}
    	printf("%d",min(f[1][0],f[1][1]));
    }
    

    资源勘探

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int P=19900907;
    int n,m,x[2000005],y1[2000005],y2[2000005],ans=0;
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    	for (int j=1;j<=m;j++)
    	{
    		int q;
    		scanf("%d",&q);
    		if (!x[q]) x[q]=i,y1[q]=j,y2[q]=m+1;
    		else
    		{
    			if (j<y1[q]) ans=(ans+(i-x[q])*(y2[q]-y1[q]))%P,x[q]=i,y2[q]=y1[q],y1[q]=j;
    			else if (j<y2[q]) ans=(ans+(i-x[q])*(y2[q]-j))%P,y2[q]=j;		
    		}
    	}
    	for (int i=1;i<=n*m;i++)
    		if (x[i]) ans=(ans+(n+1-x[i])*(y2[i]-y1[i]))%P;
    	printf("%d
    ",ans);
    }
    

    排列统计

    题目大意:对于给定的一个长度为n的序列{B[n]},问有多少个序列{A[n]}对于所有的i满足:A[1]~A[i]这i个数字中有恰好B[i]个数字小等于i。其中{A[n]}为1~n的一个排列,即1~n这n个数字在序列A[I]中恰好出现一次。数据保证了至少有一个排列满足B序列。

    这题考虑B序列的差值,非常神奇,(B_i -B_{i-1}=0,1,2)

    (f_i)表示到第(i)个数时的方案数
    情况(1)(B_i - B_{i-1}=0),因为(i)没有贡献,所以(f_i=f_{i-1})
    情况(2)(B_i - B_{i-1}=1),这时说明要么第(i)个数是(leq i),要么(1) ~ (i-1)中有一数是(=i),这是加法原理,所以(f_i=f_{i-1}*[(i-B_{i-1})+(i-B_{i-1}-1)])
    情况(3)(B_i - B_{i-1}=2),这时说明第(i)个数是(leq i)(1) ~ (i-1) 中有一数是(=i)都有,这是乘法原理,所以(f_i=f_{i-1}*(i-B_{i-1}-1)^2)
    最后(ans=f_n)

    但是,要用高精度。

    #include<cstdio>
    using namespace std;
    int f[50000];
    int n,a[50000],l;
    
    void mtlt(int k)
    {
    	int m=0;
    	for (int j=1;j<=l;j++)
    	{
    		f[j]=f[j]*k+m;
    		m=f[j]/10;
    		f[j]=f[j]%10;
    	}
    	while (m)
    	{
    		f[++l]=m;
    		m=f[l]/10;
    		f[l]=f[l]%10;
    	}
    }
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    	f[1]=1,l=1;
    	for (int i=2;i<=n;i++)
    	{
    		if (a[i]-a[i-1]==1) mtlt(i-a[i-1]+i-a[i-1]-1);
    		else if (a[i]-a[i-1]==2)mtlt((i-a[i-1]-1)*(i-a[i-1]-1));
    	}
    	for (int i=l;i>=1;i--) printf("%d",f[i]);
    }
    
  • 相关阅读:
    Maximum Flow Exhaustion of Paths Algorithm
    ubuntu下安装java环境
    visualbox使用(二)
    vxworks一个超级奇怪的错误(parse error before `char')
    February 4th, 2018 Week 6th Sunday
    February 3rd, 2018 Week 5th Saturday
    February 2nd, 2018 Week 5th Friday
    February 1st, 2018 Week 5th Thursday
    January 31st, 2018 Week 05th Wednesday
    January 30th, 2018 Week 05th Tuesday
  • 原文地址:https://www.cnblogs.com/nibabadeboke/p/13306201.html
Copyright © 2011-2022 走看看