[AtCoder] AtCoder 그랜드 대회 035 문제 해결 보고서

대회를 입력하려면 여기를 클릭

\ (A \) : XOR 원 ( 문제의 표면을 보려면 여기를 클릭 )

: 일반적으로 질문의 의미 당신 \ (N- \) 수를, 그리고 그들이 링에 링을 넣을 수 있는지 물었다 있도록 인접한 두 위치의 배타적 OR 값에 각 위치.

우선 고려하지 \ (0 \) , 우리는 첫 번째 숫자는 링이라고 가정 \ (A_1 \) , 두 번째 번호는 (A_2 \) \는 , 제 번호 \ (a_3 = A_1 \ XOR \ A_2 \ ) , 네 번째 숫자 \ (A_4 A_2 = \ XOR \ A_3 A_1 = \) . . .

법적 루프가되어야에 등등, 즉, 말을하는 것입니다 (A_1, A_2, A_1 \ \ XOR \ A_2 \) 세 가지를 반복합니다.

깔끔한, 그것은이 충족되어야하는 것입니다 :

  • 로 표시된 세 개의 숫자 총 \ (X 방향은 Y 축, Z의 \) .
  • 각각의 발생의 수.
  • \ (X \ XOR \ Y = Z의 \) .

그런 다음 우리는 특별한 고려해야합니다 \ (0 \)를 :

우선, \합니다 (N- \) \ (0 \) 반드시 합법적 인.

둘째, 경우에만 \ (0 \) 와 다른 번호 \ (X의 \)\ (X의 \) 발생 횟수입니다 (0 \)가 \ 배 수를 표시뿐만 아니라 법률 (사실,이 상황은 정상에 기인 할 수있다 ).

너무 그것을 할 수있다이어야한다. . . \ (AtCoder \) 출현 데이터,이 경우 \ (해킹 \) 데이터는 아래의 코멘트 영역에 메시지를 남길 수 있습니다.

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
using namespace std;
int n,a[N+5],s[N+5];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define tn (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        char c,*A,*B,FI[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}F;
int main()
{
    RI i,t=0;for(F.read(n),i=1;i<=n;++i) F.read(a[i]);
    for(sort(a+1,a+n+1),i=1;i<=n;++i) s[i]=a[i];t=unique(s+1,s+n+1)-s-1;//求出有几种数
    if(!a[1]&&t==1) return puts("Yes"),0;if(n%3||t>3) return puts("No"),0;//分别特判有n个0、n非3的倍数、数的种类超过3种的情况
    for(i=1;i<n/3;++i) if(a[i]^a[i+1]) return puts("No"),0;//判断第一种数是否占所有数的1/3
    for(i=n/3+1;i<n/3*2;++i) if(a[i]^a[i+1]) return puts("No"),0;//判断第二种数是否占所有数的1/3
    for(i=n/3*2+1;i<n;++i) if(a[i]^a[i+1]) return puts("No"),0;//判断第三种数是否占所有数的1/3
    return puts((a[1]^a[n/3+1])==a[n]?"Yes":"No"),0;//判断是否符合异或条件
}

\ (B의 \) : 심지어 학위 ( 문제의 표면을 보려면 여기를 클릭 )

대략 질문의 의미 : 정도의 모든 지점은 짝수 있도록, 각 에지의 방향을 결정하기 때문에, 당신에게지도를 제공합니다.

측면의 홀수 확실히 해결책입니다 찾아, 첫 문장을 어렵지 않다 해결책을 고려하지, 그것은 풀수도 확실하다.

솔루션, 우리는 먼저 작품에서 스패닝 트리, 다음 비 트리 에지 그냥 주어진 방향을 찾을 때.

다음으로, 우리는 나무를 통과.

각 지점 들어, 모든 자식 노드 처리를 완료하게 한 다음에만이 점과 부모 노드 사이의 에지의 방향을 고려한다.

현재 노드가 그의 아버지의 측면이며, 홀수의 방향 인 경우에는, 그렇지 않은 방향에서는 현재 노드의 측면이다.

이러한 방법으로 우리는 루트를 제외한 모든 노드가도 어느 정도 있음을 보장 할 수 있습니다. 그리고 가장자리의 총 수는 짝수는 짝수의 루트입니다.

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n,m,ee,d[N+5],lnk[N+5];struct edge {int to,nxt;}e[N<<1];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C==E&&(clear(),0),*C++=c)
        #define tn (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI,C=FO,E=FO+FS;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeE(Con Ty& x,Con Ty& y) {write(x),pc(' '),write(y),pc('\n');}
        I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
template<int SZ> class UnionFindSet//并查集用于找生成树时判连通性
{
    private:
        int f[SZ+5];
        I int getfa(CI x) {return f[x]?f[x]=getfa(f[x]):x;}
    public:
        I void Union(CI x,CI y) {f[getfa(x)]=getfa(y);}
        I bool Identify(CI x,CI y) {return getfa(x)==getfa(y);}
};UnionFindSet<N> U;
I void dfs(CI x,CI lst=0)//遍历树
{
    RI i;for(i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&(dfs(e[i].to,x),0);//先处理子节点
    lst&&(d[x]?F.writeE(x,lst):(d[lst]^=1,F.writeE(lst,x)),0);//根据当前节点度数奇偶性确定到父节点边的方向
}
int main()
{
    RI i,x,y;if(F.read(n,m),m&1) return puts("-1"),0;
    for(i=1;i<=m;++i) F.read(x,y),U.Identify(x,y)?
        (F.writeE(x,y),d[x]^=1):(U.Union(x,y),add(x,y),add(y,x));//生成树上边在树上连边,非树边随便定方向
    return dfs(1),F.clear(),0;
}

\ (C \) : Skolem XOR 트리 ( 문제의 표면을 보려면 여기를 클릭 )

일반적으로 문제의 의미 가있다 \ (2N \) 점, \ (나는 \)\는 (N + 내가 \) 포인트를 잘입니다 \ (나는 \)를 . 모든 있도록, 스패닝 트리 당신을 구축하기 위해 \ (나는 \) 받는 사람 \ (N + 내가 \) 나무 경로가 독점 또는이다 \ (나는 \) .

어떤 경우 먼저 고려 \ (배 \)\ (2 배 +. 1 \)를 , 만족 \ ((배) \ XOR \. (1 + 2 ×) =. 1 \) .

그래서 우리가 할 수있는 모든 \ (X 축 \ 르 \ lfloor FRAC \ N2 \ rfloor \) , 심지어 \ ((2 배) -> ( 2 배 + 1) -> (1) -> (N + 2 배) -> (N + 1 + 2 ×) \) .

그 노드에 대한 참고 \ (1 \)\ (+ \ n-1) , 우리는 심지어 \는 (2 -) \ > (N + 1) 일 수있다.

상기 절차에 따르면, 대해 \ N- (\) 홀수, 우리는 처리를 완료했다.

그러나 경우에 \ (N \)의 경우에도, 그 다음에 \ (N \)\ (2N의 \) 두 개의 노드, 우리는 건물을 완료하지 않은, 그들이 이전의 루틴에 따라 구축 할 수 없습니다.

고려 이제 문제가 스패닝 트리에 두 점을 찾을 수 있습니다, 트리 경로는 그들이 XOR 값 있도록 \ (n \) , 우리는 할 수 있습니다 \ (n \)\ (2N \) 를 각각 두 지점의 아들로.

중요한 것은, 여기 스패닝 트리 매우 특별하다! XOR 트리 경로 값은 경로의 루트 노드에 두 지점의 배타적 OR 다음 XOR입니다 \ (1 \) .

한 오픈 배럴 쉽게 검색 할 수있다.

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define add(x,y) (a[++cnt]=x,b[cnt]=y,addE(x,y),addE(y,x))
#define addE(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
using namespace std;
int n,cnt,ee,s[2*N+5],p[N<<1],lnk[2*N+5],a[N<<1],b[N<<1];struct edge {int to,nxt;}e[N<<2];
I bool dfs(CI x,CI lst=0)//找树上路径异或为n的两个点
{
    if(p[n^s[x]^1]) return add(n,p[n^s[x]^1]),add(x,n<<1),true;p[s[x]]=x;//先查询是否存在对应点,若有则建边返回true,没有则刷新桶
    for(RI i=lnk[x];i;i=e[i].nxt) if(e[i].to^lst&&(s[e[i].to]=s[x]^(e[i].to%n),dfs(e[i].to,x))) return true;//处理子节点
    return false;//找不到返回false
}
int main()
{
    RI i,j,t;if(scanf("%d",&n),n==1) return puts("No"),0;//特判n=1的情况输出无解
    for(i=2;i<n;i+=2) add(i,i+1),add(i+1,1),add(1,n+i),add(n+i,n+i+1);add(2,n+1);//对于每一对相邻的数,按套路建图
    if(!(n&1)&&!dfs(s[1]=1)) return puts("No"),0;//如果第n个点和第2n个点找不到位置安放,输出无解
    for(puts("Yes"),i=1;i<=cnt;++i) printf("%d %d\n",a[i],b[i]);//输出
    return 0;
}

\ (D \) : 추가 및 제거 ( 문제의 표면을 보려면 여기를 클릭 )

질문의 대략 의미 : 당신에게 순서, 당신이 번호를 삭제할 수 있습니다 때마다, 그래서면의 수를 더한이 번호의 값이 최소 수와 마지막 남은를 제공합니다.

우리는 고려할 수 있습니다 \합니다 (DFS를 \) .

해결책은 현재 구간 세트 (\ [L, R & LT] \) , 좌측 지점을 계산 간격 \ (TL \) 번 우단 포인트 계산 \ (TR \) 번.

그렇다면 우리는이 범위 내의 마지막 수 제거한 열거 할 수 는 (i \) \ 다음 횟수은 그 계산 된 \ (TL + TR \) .

우리는 재귀 서브 섹션 처리 \을 ([L, I] \ ) 와 \ ([I, R & LT] \) 통계적 최소.

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 18
#define LL long long
#define RL Reg LL
#define CL Con LL&
#define INF 1e18
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
int n,a[N+5];
I LL dfs(CI l,CI r,CL tl,CL tr)//dfs
{
    if(r-l==1) return 0;RL t,res=INF;//若只剩左右端点,返回0
    for(RI i=l+1;i^r;++i) t=dfs(l,i,tl,tl+tr)+dfs(i,r,tl+tr,tr)+a[i]*(tl+tr),Gmin(res,t);//枚举最后被删除的数,递归子区间
    return res;//返回答案
}
int main()
{
    RI i;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d",a+i);//读入
    return printf("%lld",dfs(1,n,1,1)+a[1]+a[n]),0;//求解
}

\ (E \) : 개발 ( 문제의 표면을 보려면 여기를 클릭 )

이 제목입니다 (BZT의 \) \ 신들 때 시뮬레이션 대회 타이틀을 움직였다.

: 해석이 블로그 볼 수 있습니다 [2019년 8월 11일 아침 계 시뮬레이션 게임 T2] 십칠kg 무게 문명 (세븐틴)를 .

\ (F \) : 히스토그램 두 ( 문제의 표면을 보려면 여기를 클릭 )

일반적으로, 질문의 의미 소정 (n 개 * m 개의 \) \ 행렬, 각 행을 결정 \ (k_i∈ [0, m] \) , (A)의 각 열에 대해 \ (l_i∈ [0, N-] \) , 매트릭스 \ ((I, J) \ ) 의 위치 값이다 (\ [J \ 르 K_i] + \ [I 르가 l_j \]) , 다양한 기질을 요구했다.

우리는을위한 시퀀스의 집합 고려 \ (K, L의 \)를 , 그들을 대표하는 통일 된 방법을 찾아, 행렬의 같은 행렬 표현 결과 동일한 구성은, 다른 구성되도록.

이어서이 경우, 발견 될 수 드로잉 (엑스 \) \\ (Y의 \) 을 만족 \ (K_x + 1 = Y- \를 \ L_y는 X- \ =) , 우리는 수 (\ k_x \) 플러스 \ (1 \을 ) , \ (L_y \) 저장 \ (1 \) .

그래서 우리는 얼마나 많은 그룹 알아 할 \ (K, L을 \) 가되도록 \ (x는, y를 \)이 위의 기준을 충족합니다.

이 포함 및 배제.

의 존재하에 사용하는 \ (X, Y의 \) 로 로그인 \ (\ ge0 \) 번호 반응식 마이너스의 대수 \ (\ GE1은 \) 번호 체계, 수 결합 (\ GE2 \) \ 번호 체계, 등등.

획득하기위한 요구를 제공 (\ GE의 X \) \ 된 프로그램의 수, 우리 제 \ (K \) 선택된 \ (X \) 의 위치, 다음 \ (L의 \) 에서 찍은 \ (X \) 의 위치, 다만 나머지를 입력, 즉 :

\ [C_n ^ X ^ A_m * X * (N + 1) ^ {MX} * (m + 1) ^ {NX} \]

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500000
#define X 998244353
#define swap(x,y) (x^=y^=x^=y)
#define Qinv(x) Qpow(x,X-2)
#define A(x,y) (1LL*Fac[x]*IFac[(x)-(y)]%X)
#define C(x,y) (1LL*A(x,y)*IFac[y]%X)
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
using namespace std;
int n,m,Fac[N+5],IFac[N+5],Pn[N+5],Pm[N+5];
I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
    RI i,t,ans=0;scanf("%d%d",&n,&m),n>m&&swap(n,m);
    for(Fac[0]=Pn[0]=Pm[0]=i=1;i<=m;++i)//预处理
        Fac[i]=1LL*Fac[i-1]*i%X,Pn[i]=1LL*Pn[i-1]*(n+1)%X,Pm[i]=1LL*Pm[i-1]*(m+1)%X;
    for(IFac[m]=Qinv(Fac[m]),i=m-1;~i;--i) IFac[i]=1LL*IFac[i+1]*(i+1)%X;
    for(i=0;i<=n;++i) t=1LL*C(n,i)*A(m,i)%X*Pn[m-i]%X*Pm[n-i]%X,Inc(ans,i&1?X-t:t);//容斥
    return printf("%d",ans),0;//输出答案
}

추천

출처www.cnblogs.com/chenxiaoran666/p/AtCoderAGC035.html