• 2020.10.13 dxm 讲题


    st0 dxm,yht 的没听了(

    CF938F - Erasing Substrings

    题解

    CF995C - Leaving the Bar

    Portal

    考虑归纳,试图合并两个向量使得 (n) 减少 (1)

    考虑如果直接合并随意的两个向量。那么最差的情况就是两个向量是垂直的,这时候斜边大于直角边。如果两个边相等都等于 (a) 的话,那么合并出来的长度就是 (sqrt2a)。很显然,把 (10^6) 乘两遍 (sqrt2) 你就没掉了。总之这种 naive 的方法是不行的。况且归纳本来就要求除了规模缩小之外,其他条件都不变,而这里显然可能将值域扩大。

    注意到两个向量的长度固定了之后,影响他们的和的长度的只有它们的夹角。先不严谨地设它们长度相等,都等于 (x)。那么考虑到等边三角形,显然有它们的和的长度 (leq x) 当且仅当夹角 (alphaleq 60^circ)。但是有可能它们的长度不相等,这时候我们需要证明一下 (xleq) 较长边。

    其实并不难证明。如图,(oldsymbol a=overrightarrow{OP}) 为第一个向量(较大),分别以 (O,P) 为圆心,(OP) 为半径作圆。那么第二个向量 (oldsymbol b) 显然为 (O)(OQ,OQ',OQ'') 上任意一点的连线,其中 (OQ,OQ',OQ'') 分别为夹角 (<,=,> 60^circ) 的三种情况。那么 (|oldsymbol a+oldsymbol b|leq |oldsymbol a|) 显然当且仅当该夹角 (alpha) 下的 (OQ) 完全在圆 (P) 内,肉眼可见 (alphaleq 60^circ)

    有了这个结论就不难想到做法了。我们找任意三条向量,它们中夹角最小的一对的夹角显然要 (leqdfrac{360^circ}6=60^circ),那么每次可以选择这组向量合并来归纳。到最后还剩 (n=2) 的时候,不能保证能找到这组向量了,不过这是无所谓了,乘个 (sqrt2) 恰好增长不到 (1.5) 倍。

    接下来考虑实现细节:

    • 我不会算向量夹角,不过无伤大雅。只需要每次找到所有可能合成的向量中最短的那个即可。
    • 如何合并?需要做的操作是将当前一个向量取反,而任意时刻一个向量可能是多个原向量的化合物,暴力取反大概会炸。考虑到每次恰好合并两个,那就建一棵二叉树,合并用虚拟节点连接两个根,打标记(就是树上差分),最后 DFS 一遍即可。一开始觉得很奇怪,但后来发现和 official solution 重合?然后发现其实还可以无脑启发式。
    #include<bits/stdc++.h>
    using namespace std;
    #define mp make_pair
    #define X first
    #define Y second
    #define pb push_back
    #define ppb pop_back
    const double inf=1e14;
    const int N=100000;
    int n;
    pair<int,int> a[2*N+1];
    int son[2*N+1][2],prod[2*N+1][2];
    vector<int> v;
    pair<int,int> operator+(pair<int,int> x,pair<int,int> y){return mp(x.X+y.X,x.Y+y.Y);}
    pair<int,int> operator*(int x,pair<int,int> y){return mp(x*y.X,x*y.Y);}
    pair<int,int> operator-(pair<int,int> x,pair<int,int> y){return x+(-1)*y;}
    double len(pair<int,int> x){return sqrt(1ll*x.X*x.X+1ll*x.Y*x.Y);}
    int ans[N+1];
    void dfs(int x=2*n-1,int now=1){
    	if(x>n){
    		dfs(son[x][0],now*prod[x][0]);
    		dfs(son[x][1],now*prod[x][1]);
    	}
    	else ans[x]=now;
    }
    int main(){
    	cin>>n;
    	if(n==1)return puts("1"),0;
    	for(int i=1;i<=n;i++)scanf("%d%d",&a[i].X,&a[i].Y),v.pb(i);
    	for(int i=1;i<=n-2;i++){
    		int x=v.back();v.ppb();
    		int y=v.back();v.ppb();
    		int z=v.back();v.ppb();
    		pair<double,pair<pair<int,int>,pair<int,int> > > mn;
    		mn.X=inf;
    		mn=min(mn,mp(len(a[x]+a[y]),mp(mp(x,1),mp(y,1))));
    		mn=min(mn,mp(len(a[x]-a[y]),mp(mp(x,1),mp(y,-1))));
    		mn=min(mn,mp(len(a[x]+a[z]),mp(mp(x,1),mp(z,1))));
    		mn=min(mn,mp(len(a[x]-a[z]),mp(mp(x,1),mp(z,-1))));
    		mn=min(mn,mp(len(a[y]+a[z]),mp(mp(y,1),mp(z,1))));
    		mn=min(mn,mp(len(a[y]-a[z]),mp(mp(y,1),mp(z,-1))));
    		a[i+n]=mn.Y.X.Y*a[mn.Y.X.X]+mn.Y.Y.Y*a[mn.Y.Y.X];
    		son[i+n][0]=mn.Y.X.X,prod[i+n][0]=mn.Y.X.Y;
    		son[i+n][1]=mn.Y.Y.X,prod[i+n][1]=mn.Y.Y.Y;
    		v.pb(i+n);
    		if(son[i+n][0]==x&&son[i+n][1]==y)v.pb(z);
    		if(son[i+n][0]==x&&son[i+n][1]==z)v.pb(y);
    		if(son[i+n][0]==y&&son[i+n][1]==z)v.pb(x);
    	}
    	int x=v.back();v.ppb();
    	int y=v.back();v.ppb();
    	pair<double,pair<pair<int,int>,pair<int,int> > > mn;
    	mn.X=inf;
    	mn=min(mn,mp(len(a[x]+a[y]),mp(mp(x,1),mp(y,1))));
    	mn=min(mn,mp(len(a[x]-a[y]),mp(mp(x,1),mp(y,-1))));
    	a[2*n-1]=mn.Y.X.Y*a[mn.Y.X.X]+mn.Y.Y.Y*a[mn.Y.Y.X];
    	son[2*n-1][0]=mn.Y.X.X,prod[2*n-1][0]=mn.Y.X.Y;
    	son[2*n-1][1]=mn.Y.Y.X,prod[2*n-1][1]=mn.Y.Y.Y;
    	dfs();
    	for(int i=1;i<=n;i++)printf("%d ",ans[i]);
    	return 0;
    }
    

    CF1178H - Stock Exchange

    鸽子

    CF1109F - Sasha and Algorithm of Silence's Sounds

    鸽子

    CF960G - Bandit Blues

    鸽子

    CF1338E - JYPnation

    鸽子

  • 相关阅读:
    Android 逐帧动画
    MAP getLastKnownLocation()返回null的解决
    大数取余
    (a^b)%c和(a/b)%c
    HDU1046 Gridland
    顺序入栈的出栈方法种数
    HDU1021 Fibonacci Again
    HDU1019 Least Common Multiple
    HDU1018 Big Number
    HDU1013 Digital Roots
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/20201013-dxm.html
Copyright © 2020-2023  润新知