C. Three Circuits
首先显然需要有欧拉回路,即所有点度数都是偶数。
假如有 $6$ 度的点或者超过两个 $4$ 度点一定合法。如果不到两个 $4$ 度点就不合法。
当有两个 $4$ 度点时,考虑是否连成两个环,直接删去一个 $4$ 度点后判是否连通即可。
复杂度 $O(n)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<iostream> #include<cstdio> #include<cstring> #define N 200010 using namespace std; int f[N]; int find(int x){return f[x]==x?f[x]:(f[x]=find(f[x]));} int x[N],y[N],d[N]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]),d[x[i]]++,d[y[i]]++; for(int i=1;i<=n;i++) if(d[i]&1){puts("No");return 0;} for(int i=1;i<=n;i++) if(d[i]>4){puts("Yes");return 0;} int c=0; for(int i=1;i<=n;i++) if(d[i]==4) c++; if(c>2){puts("Yes");return 0;} if(c<2){puts("No");return 0;} for(int i=1;i<=n;i++) if(d[i]==4){c=i;break;} for(int i=1;i<=n;i++) f[i]=i; for(int i=1;i<=m;i++) if(x[i]!=c && y[i]!=c) f[find(x[i])]=find(y[i]); int d=find(c==1?2:1); for(int i=1;i<=n;i++) if(i!=c && find(i)!=d){puts("Yes");return 0;} puts("No"); return 0; }
|
D. Rotation Sort
可以发现 $1$ 操作本质上是将一个数往右插,$2$ 就是把一个数往左插。
从左往右处理,考虑一个数如果向右插,等同于将其扔掉(直接计入答案)。所以考虑维护一个上升的序列表示没有向右插的集合。显然只要记录这个序列的最大值即可。
用 $f_{i,j}$ 表示前 $i$ 个数,上升序列最大值为 $j$ 的最小代价。
考虑新加数为 $x$,如果 $x>j$ 那么可以向右插或者加入序列。如果 $x<j$ 就只能向左插入序列。
复杂度 $O(n^2)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<iostream> #include<cstdio> #include<cstring> #define N 5010 #define ll long long using namespace std; ll f[N][N]; int p[N]; void chkmin(ll &x,ll y){x=min(x,y);} int main() { int n,a,b; scanf("%d%d%d",&n,&a,&b); for(int i=1;i<=n;i++) scanf("%d",&p[i]); memset(f,0x3f,sizeof(f)); f[0][0]=0; for(int i=1;i<=n;i++) for(int j=0;j<=n;j++) { if(p[i]<j) chkmin(f[i][j],f[i-1][j]+b); else chkmin(f[i][j],f[i-1][j]+a),chkmin(f[i][p[i]],f[i-1][j]); } ll ans=1e16; for(int i=1;i<=n;i++) ans=min(ans,f[n][i]); printf("%lld\n",ans); return 0; }
|
E. Modulo Pairing
显然只有两种可能:相加不超过 $M$ 与超过 $M$。
考虑先将原序列排序,可以证明,一定存在一个分界线,满足分界线左边右边各自首尾匹配。具体证明分类讨论一下即可。
右边部分显然要所有匹配 $>m$,而右边和显然是单减的,所以可以二分。
总复杂度 $O(n\log n)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 200010 #define ll long long using namespace std; int a[N],n,m,ans=2e9; bool check(int x) { for(int i=1;2*x+2*i<=2*n;i++) if(a[2*x+i]+a[2*n-i+1]<m) return false; return true; } void upd(int x) { int res=0; for(int i=1;i<=x;i++) res=max(res,(a[i]+a[2*x-i+1])%m); for(int i=1;2*x+2*i<=2*n;i++) res=max(res,(a[2*x+i]+a[2*n-i+1])%m); ans=min(ans,res); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=2*n;i++) scanf("%d",&a[i]); sort(a+1,a+2*n+1); int l=0,r=n; while(l<=r) { int mid=(l+r)>>1; if(check(mid)) upd(mid),r=mid-1; else l=mid+1; } printf("%d\n",ans); return 0; }
|
F. One Third
考虑距离 $\frac 13$ 最近很难做,如果将序列每 $\frac 13$ 分成一块并且映射到一起,可以发现任意两个不同色的点之间距离就是到 $\frac 13$ 的距离。
这样转化为 $n$ 个点之间的不同色点距离最小值。
考虑一个式子:
$$
E(L_{k})=\frac 1n\left(\sum_{0<i<k}\frac 1{n-i}\right)
$$
其中 $L_{k}$ 表示第 $k$ 小的距离。具体证明可以用 min-max 容斥然后随便推一推。
这样枚举 $n$ 个点之间第 $k$ 对相邻点是第一对不同色点,那么前 $k$ 对一定是同色点,有:
$$
ans=\frac 1{3n}\sum_{i=1}^n\left(\frac{1}{3^{i-1}}-\frac{1}{3^i}\right)\sum_{j<i}\frac1{n-i}
$$
直接处理即可,复杂度 $O(n)$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<iostream> #include<cstdio> #include<cstring> #define N 1000010 #define mod 1000000007 using namespace std; int ksm(int a,int b=mod-2) { int r=1; for(;b;b>>=1) { if(b&1) r=1ll*r*a%mod; a=1ll*a*a%mod; } return r; } int _3[N]; int main() { int n; scanf("%d",&n); _3[1]=ksm(3),_3[0]=1; for(int i=2;i<n;i++) _3[i]=1ll*_3[i-1]*_3[1]%mod; int ans=0,res=ksm(n); for(int i=1;i<=n;i++) { ans=(ans+1ll*(_3[i-1]-_3[i])%mod*res)%mod; res=(res+ksm(n-i))%mod; } printf("%lld\n",1ll*ans*ksm(3*n)%mod); return 0; }
|