• 联考20200603 T2 排列


    题目:


    分析:
    把排列看做一个(n)维上的点,(n!)个排列会在(n)维空间下构成一个凸包
    如果输入的排列表示的点是在凸包上,那么就一定有解
    什么玄学玩意?
    其实原序列为(X),假设(X)从小到大排序后的序列为(Y),如果有解,当且仅当满足下面两个条件:

    (sum_{i=1}^{n}Y_i=frac{n(n+1)}{2})
    (sum_{i=1}^{k}Y_igeq frac{k(k+1)}{2})

    其中(k)(1)(n)的整数
    冷静分析一下:
    第一个式子由于(a_i=sum_{j=1}^{m}p_{j}b_{ij}),求和即可证明
    转化到凸包上,每一个点到原点的曼哈顿距离都是(frac{n(n+1)}{2}),都可以用(n!)个排列形成的向量乘以模长(p)表示
    第二个式子需要我们重新理解一下整个过程
    我们可以将整个过程理解为,下标小的数需要下标大的数匀一些值过来,我们要求的便是匀过来值的占比
    而如果一个前缀他自身需要的值比(frac{k(k+1)}{2})小,后面的数匀过来只会让它变大,无解
    转化到凸包上,不合法的点会在凸包某一个(n-1)维的面上,但是不会再凸包上,无法表示

    我们先把序列排序形成(Y),用(1...n)的序列作为向量(a)乘以尽量长的(p)来表示
    假设我们求出了一个(p),向量(pa)从原点出发,终点假设为(A)
    凸包上,每一个点到(A)的曼哈顿距离都是(frac{(1-p)n(n+1)}{2}),这个不难看出
    那么原序列向量(Y)减去向量(pa),然后从小到大排序得到的(Y')依然要满足:

    (sum_{i=1}^{n}Y'_i=frac{(1-p)n(n+1)}{2})
    (sum_{i=1}^{k}Y'_igeq frac{(1-p)k(k+1)}{2})

    证明与上面同理
    我们可以二分出最大的(p),递归求解即可,由于每一次一定会有某一维达到瓶颈,我们最多只需要做(n)

    神仙题,可能讲不大清楚,先口胡这么长一段(
    看代码可能能帮助理解

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<iostream>
    #include<map>
    #include<bitset>
    #include<string>
    
    #define maxn 40005
    #define INF 1<<30
    #define eps 1e-13
    
    using namespace std;
    
    inline long long getint()
    {
        long long num=0,flag=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
        while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
        return num*flag;
    }
    
    int n;
    struct node{
    	long double a;
    	int id;
    }A[maxn];
    inline bool cmp(node x,node y){return x.a<y.a;}
    long double B[maxn];
    int sum;
    int ans[maxn];
    
    int main()
    {
    	n=getint();
    	for(int i=1;i<=n;i++)
    	{
    		int x=getint();
    		sum+=x,A[i].a=x;A[i].id=i;
    	}
    	if(sum!=n*(n+1)/2){puts("-1");return 0;}
    	sort(A+1,A+n+1,cmp);
    	long double num=0,now=1;
    	for(int i=1;i<=n;i++)
    	{
    		num+=A[i].a;
    		if(num<i*(i+1)/2){puts("-1");return 0;}
    	}
    	printf("%d
    ",n);
    	for(int t=1;t<=n;t++)
    	{
    		sort(A+1,A+n+1,cmp);
    		long double l=0,r=now;
    		while(r-l>eps)
    		{
    			long double mid=(l+r)/2;bool flg=0;
    			for(int i=1;i<=n;i++)
    			{
    				B[i]=A[i].a-mid*i;
    				if(B[i]<-eps){flg=1;break;}
    			}
    			sort(B+1,B+n+1);
    			long double num=0;
    			for(int i=1;i<=n;i++)
    			{
    				num+=B[i];
    				if(num+eps<(now-mid)*i*(i+1)/2){flg=1;break;}
    			}
    			if(flg)r=mid;
    			else l=mid;
    		}
    		printf("%.12lf",(double)l);now-=l;
    		for(int i=1;i<=n;i++)ans[A[i].id]=i,A[i].a-=l*i;
    		for(int i=1;i<=n;i++)printf(" %d",ans[i]);
    		printf("
    ");
    	}
    }
    

  • 相关阅读:
    java1234初学maven
    解决maven创建web项目卡死在generator插件(转)
    maven下载速度慢的解决方法(转)
    git分支
    git基础
    oracle分析函数与over()(转)
    Oracle开窗函数 over()(转)
    Oracle计算时间函数(对时间的加减numtodsinterval、numtoyminterval) (转)
    selenium使用中遇到的问题
    selenium运行火狐报错FirefoxDriver : Unable to connect to host 127.0.0.1 on port 7055
  • 原文地址:https://www.cnblogs.com/Darknesses/p/13040385.html
Copyright © 2020-2023  润新知