Codeforces Round #395 (Div. 2)

传送门

题意

B.将cube顺序复原
C.无根转有根树,并且对于(除去顶点)的每棵子树,其顶点颜色相同
D.给出n个平行于坐标轴的边长为奇数的矩形,矩形接触而不覆盖,将其染色,接触矩形颜色不同,给出一种可行方案
E.给出n个模m的数(乱序),问是否构成等差数列,是则给出首项及方差,否则输出NO

题解

B.从两端往中间扫,复杂度\(O(n)\)
C.引用renadeen的解释

I have a simpler solution. Take all edges that connect vertices of different colors. If all these edges have one common vertex — this vertex is the answer. Otherwise the answer is NO.

所以只要找到一个顶点能在所有不同颜色的边中即可
图形解释
一种sample的解释

D.根据四色定理可知必存在满足情况
对于某一矩形来说,若不与其他矩形接触,则任意颜色即可;
若与其他矩形接触,可以发现,由于边长为\(odd%=\),对于左下角而言,其\((x&1+y&1+1)\)必定不相同,可根据此来构造,引用ljh2000的话:

Consider a rectangle,we have know that rectangles cannot intersect,and all sides of the rectangles have odd length.As we all know,the Four color theorem,so it must have a solution.What we need to do is to find a solution to give a color to every rectangle.If the lower left quarter of the rectangle,\((x1,y1)\),so that we can know the situation of \((x1+odd,x2+odd)\),we can confirm that we just need to color the rectangle according to its \(x1\) and \(y1\)'s parity.

E.参考ljh2000blog
引用\(ChamrAn\)的代码(与blog方法不同)

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 100010;

int n,m,a[N],b[N];
int ans,ansd;

inline LL Pow(LL a,int x,int mod){
	LL res=1;
	for(;x;x>>=1,a=a*a%mod) if(x&1) res=res*a%mod;
	return res;
}

void solve(int *a,int n){
	int gap=a[1]-a[0],cnt=0;a[n]=-1;
	for(int i=0;i<n;i++) if(binary_search(a,a+n,(a[i]+gap)%m)) cnt++;
	int k=n-cnt,d= Pow(k,m-2,m) * gap % m ;
	ans=-1;ansd=(m-d)%m;
	for(int i=0;i<n;i++) if(!binary_search(a,a+n,(a[i]+d)%m))
		if(ans==-1) ans=a[i]; else {ans=-1;return;}
}
int main()
{
	scanf("%d%d",&m,&n);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	if(n==1 || n==m) return printf("%d 1\n",a[0]),0;
	sort(a,a+n);
	if(2*n<m) solve(a,n);
	else{
		int t=0;
		for(int i=0;i<m;i++) if(!binary_search(a,a+n,i)) b[t++]=i;
		solve(b,t);if(ans!=-1) (ans+=1ll*ansd*t%m)%=m;
	}
	if(ans==-1) printf("-1\n");
	else printf("%d %d\n",ans,ansd);
	return 0;
}

提供一种\(divE\)不同与\(Editorial\)的做法(来源于\(quality\))
检查所有的\(d=a[i]-a[1]\),并用\(d\)\(sum\)求出首项\(tmp\),再求出所有项的平方和\(ret\), 与原来输入的数平方和比较,若相同,则用\(d\)\(tmp\)求出所有的项,并\(check\), 若成功,则输出\(d\)\(tmp\), 总共\(check\)次数不超过\(2\)

In order to meet the conditions for which this algorithm can work, we consider only p which is odd and n<m-1. While there is no deterministic way for solving an arbitrary quadratic equation, it can easily be transformed into y^2 = d (mod p) where the Cipolla algorithm allows us to solve with approximately 1/2 probability for each random number. So, the expected value is 2. The overall complexity is O(n log n + k log p), where k is the number of tries in the Cipolla algorithm. It can be quite high for the problem conditions, so although there is a probability for failure, it is very small.(\(gsCEA\)

Nice solution! And in fact, you can simply try all a[i]-a[1] as d and find x with x+(x+d)+...+(x+(n-1)d) equals to the sum of the elements. As you have said, there are at most two pairs (x,d) which satisfy x2+(x+d)2+...+(x+(n-1)d)^2 equals to the sum of square. So we can check these two pairs by brute force.
\(quailty\)
(若有错误轻喷)

附代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define ll long long
inline void read(int &x){x=0; char ch=getchar();while(ch<'0') ch=getchar();while(ch>='0'){x=x*10+ch-48; ch=getchar();}}

int m,n;
ll tmp,s[2]={0,0},b[100100],a[100100];
ll do_exp(int a,int p)
{
    ll ret=1;
    for(;p;p>>=1,a=1LL*a*a%m) if(p&1) (ret=ret*a)%=m;
    return ret;
}

int main()
{
    scanf("%d %d",&m,&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%lld",a+i);(s[0]+=a[i])%=m;(s[1]+=a[i]*a[i])%=m;
    }
    if(n==1) { printf("%lld 0\n",a[1]);return 0; }
    if(n==m) { puts("0 1");return 0; }
    sort(a+1,a+1+n);
    //printf("%lld %lld\n",s[0],s[1]);
    for(int i=2;i<=n;++i)
    {
        int d=(a[i]-a[1])%m;
        tmp=(s[0]-1LL*n*(n-1)/2%m*d%m+m)%m*do_exp(n,m-2)%m;
        //printf("tmp=%lld\n",tmp);
        ll ret=(1LL*n*tmp%m*tmp%m+1LL*n*(n-1)%m*tmp%m*d%m+1LL*(n-1)*n*(2*n-1)/6%m*d%m*d%m)%m;
        //printf("ret=%lld\n",ret);
        if(ret==s[1])
        {
            b[1]=tmp;
            for(int i=2;i<=n;++i) b[i]=(b[i-1]+d)%m;
            sort(b+1,b+1+n);
            //for(int i=1;i<=n;++i) printf("b[%d]=%d%c",i,b[i],i==n?'\n':' ');
            bool flag=1;
            for(int i=1;i<=n;++i) flag&=(a[i]==b[i]);
            if(flag) {printf("%lld %d\n",tmp,d);return 0;}
        }
    }
    puts("-1");
    return 0;
}
posted @ 2017-02-03 18:13  遗风忘语  阅读(143)  评论(0编辑  收藏  举报