• XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Korea


    A. Donut

    扫描线+线段树。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=800010,M=2222222;
    int n,m,cnt,i,j;ll L,R,D,a[N];
    int tag[M],v[M],ans;
    struct E{
    	ll x,l,r;int s;
    	E(){}
    	E(ll _x,ll _l,ll _r,int _s){x=_x,l=_l,r=_r,s=_s;}
    }e[N];
    inline bool cmp(const E&a,const E&b){return a.x<b.x;}
    inline void tag1(int x,int p){tag[x]+=p;v[x]+=p;}
    void add(int x,int a,int b,int c,int d,int p){
    	if(c<=a&&b<=d){
    		tag1(x,p);
    		return;
    	}
    	if(tag[x])tag1(x<<1,tag[x]),tag1(x<<1|1,tag[x]),tag[x]=0;
    	int mid=(a+b)>>1;
    	if(c<=mid)add(x<<1,a,mid,c,d,p);
    	if(d>mid)add(x<<1|1,mid+1,b,c,d,p);
    	v[x]=max(v[x<<1],v[x<<1|1]);
    }
    int main(){
    	scanf("%d%lld%lld",&n,&L,&R);L--;
    	while(n--){
    		ll x,y;
    		int s;
    		scanf("%lld%lld%d",&x,&y,&s);
    		e[++m]=E(x-R,y-R,y+R,s);
    		e[++m]=E(x+R+1,y-R,y+R,-s);
    		e[++m]=E(x-L,y-L,y+L,-s);
    		e[++m]=E(x+L+1,y-L,y+L,s);
    	}
    	for(i=1;i<=m;i++)a[++cnt]=e[i].l,a[++cnt]=e[i].r;
    	sort(a+1,a+cnt+1);
    	sort(e+1,e+m+1,cmp);
    	for(i=1;i<=m;i=j){
    		for(j=i;j<=m&&e[i].x==e[j].x;j++)add(1,1,cnt,lower_bound(a+1,a+cnt+1,e[j].l)-a,lower_bound(a+1,a+cnt+1,e[j].r)-a,e[j].s);
    		ans=max(ans,v[1]);
    	}
    	printf("%d",ans);
    }
    

      

    B. Circular Arrangement

    留坑。

    C. Earthquake

    对于一条路径内部来说,最优策略肯定是从存在概率最小的开始询问。

    对于不同路径之间来说,考虑排序不等式贪心即可。

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<string>
    #include<ctype.h>
    #include<math.h>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<bitset>
    #include<algorithm>
    #include<time.h>
    using namespace std;
    void fre() {  }
    #define MS(x, y) memset(x, y, sizeof(x))
    #define ls o<<1
    #define rs o<<1|1
    typedef long long LL;
    typedef unsigned long long UL;
    typedef unsigned int UI;
    template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
    template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
    const int N = 1010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n;
    double a[N];
    long double win[N], fail[N];
    struct A
    {
    	long double failp;
    	long double step;
    	bool operator < (const A & b) const
    	{
    		long double afirst = step + failp * b.step;
    		long double bfirst = b.step + b.failp * step;
    		return afirst < bfirst;
    	}
    }v[N];
    int main()
    {
    	while(~scanf("%d",&n))
    	{
    		for(int i = 1; i <= n; ++i)
    		{
    			int g; scanf("%d", &g);
    			for(int j = 1; j <= g; ++j)
    			{
    				scanf("%lf", &a[j]);
    				a[j] /= 1000;
    			}
    			sort(a + 1, a + g + 1);
    			win[0] = 1;
    			fail[0] = 0;
    			v[i].step = 0;
    			for(int j = 1; j <= g; ++j)
    			{
    				win[j] = win[j - 1] * a[j];
    				fail[j] = fail[j - 1] + win[j - 1] * (1 - a[j]);
    				v[i].step += win[j - 1] * (1 - a[j]) * j;
    			}
    			v[i].step += win[g] * g;
    			v[i].failp = fail[g];
    		}
    		sort(v + 1, v + n + 1);
    		long double ans = 0;
    		long double p = 1;
    		for(int i = 1; i <= n; ++i)
    		{
    			ans += p * v[i].step;
    			p *= v[i].failp;
    		}
    		printf("%.12f
    ", (double)ans);
    	}
    	return 0;
    }
    
    /*
    【trick&&吐槽】
    2
    3 900 900 900
    2 100 100
    
    3
    1 240
    1 310
    1 50
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    D. Dynamic Input Tool

    贪心,若不是子序列则进行一次操作。

    #include<cstdio>
    #include<cstring>
    const int N=1000010;
    int n,i,j,f[N][26];
    int l,r,x,ans;
    int vis[26];
    char a[N];
    int main(){
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	for(i=1;i<=n;i++)a[i]-='a';
    	for(j=0;j<26;j++)f[n+1][j]=n+1;
    	for(i=n;i;i--){
    		for(j=0;j<26;j++)f[i][j]=f[i+1][j];
    		f[i][a[i]]=i;
    	}
    	for(i=1;i<=n;i++){
    		if(!vis[a[i]]){
    			if(l&&l<i)ans++;
    			vis[a[i]]=1;
    			ans++;
    			l=i+1;
    			x=1;
    		}else{
    			x=f[x][a[i]];
    			if(x>=l){
    				ans++;
    				x=f[1][a[i]];
    				l=i;
    			}
    			x++;
    		}
    	}
    	if(l<=n)ans++;
    	printf("%d",ans);
    }
    

      

    E. Central Lake

    答案即为圆周上距离最远的两个点的距离,求出两个点后可以求切线得出答案。

    对于求最远点对,可以使用set支持插入操作,对于删除则按时间分治即可。

    时间复杂度$O(nlog^2n)$。

    #define ms(x, y) memset(x, y, sizeof(x))
    #define mc(x, y) memcpy(x, y, sizeof(x))
    #define mid (l+r>>1)
    #define lson o << 1, l, mid
    #define rson o << 1 | 1, mid + 1, r
    #define ls o << 1
    #define rs o << 1 | 1
    #define rt 1,1,Q+1
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<queue>
    #include<map>
    #include<stack>
    #include<vector>
    #include<list>
    #include<set>
    #include<string>
    #include<algorithm>
    #pragma comment(linker,"/STACK:102400000,102400000")
    template <class T> inline void gmax(T &a, T b){if(b > a) a = b;}
    template <class T> inline void gmin(T &a, T b){if(b < a) a = b;}
    using namespace std;
    const int N = 4e5 + 10, M = 1e6 + 10, Z = 1e9 + 7, maxint = 2147483647, ms1 = 16843009, ms31 = 522133279, ms63 = 1061109567, ms127 = 2139062143;
    const double PI = acos(-1.0), eps = 1e-8;
    double R, r;
    int n;
    int LL, RR, X;
    vector<int> w[N], v[N * 4];
    int a[N];
    
    /*
    const int BS = 360000;
    struct point{
        long double x, y, z;
        point(){}
        point (long double x_,long double y_,long double z_=1.0){x=x_,y=y_,z=z_;}
        point operator -(const point &p)const{
            return {x-p.x,y-p.y};
        }
        point operator +(const point &p)const{
            return {x+p.x,y+p.y};
        }
        point operator *(const long double &k)const{
            return {x*k,y*k};
        }
        long double Norm(){
            return sqrtl(x*x+y*y);
        }
        point Rotate(const long double &AA)const{
            long double c = cosl(AA);
            long double s = sinl(AA);
            return {c*x-s*y, x*s+c*y};
        }
    }O;
    point Seg(point a, point b){
        return {b.y-a.y,a.x-b.x,-a.x*b.y+a.y*b.x};
    }
    long double val(int d){
        long double AA = (long double)d/BS * 2*PI;
        point p = {(long double)R, (long double)0};
        point q = {R*cosl(AA), R*sinl(AA)};
        point S = Seg(p,q);
        long double dis = S.z/sqrtl(S.x*S.x+S.y*S.y);
        if(dis<0)dis=-dis;
        if(dis > r){
            return (q-p).Norm();
        }
        long double BB = asinl((long double)r/R);
        point v1 = (O-q).Rotate(BB);
        long double dd = sqrtl((long double)R*R-(long double)r*r);
        v1 = q + v1*((long double)1.0/v1.Norm()*dd);
        point v2 = (O-p).Rotate(-BB);
        v2 = p + v2*((long double)1.0/v2.Norm()*dd);
        return (q-v1).Norm() + (p-v2).Norm() + (atan2l(v1.y,v1.x) - atan2l(v2.y,v2.x))*r;
    }
    */
    
    struct Point
    {
        double x, y;
        Point(double x_, double y_){ x = x_; y = y_; }
        friend Point operator - (const Point &a, const Point &b){
            return Point(a.x - b.x, a.y - b.y);
        }
        friend Point operator + (const Point &a, const Point &b){
            return Point(a.x + b.x, a.y + b.y);
        }
        friend Point operator * (const Point &a, const double &b){
            return Point(a.x * b, a.y * b);
        }
        friend Point operator / (const Point &a, const double &b){
            return Point(a.x / b, a.y / b);
        }
        double len2(){
            return x * x + y * y;
        }
        double len()
        {
            return sqrt(len2());
        }
        Point rotate(const double ang){
            return Point(cos(ang) * x - sin(ang) * y, cos(ang) * y + sin(ang) * x);
        }
        Point turn90(){
            return Point(-y, x);
        }
    };
    struct Circle
    {
        Point o;
        double r;
        Circle(Point o = Point(0, 0), double r = 0) : o(o), r(r) {}
    };
    
    vector<Point> circleTangentPoint(const Circle &c, const Point &p0)
    {
        double x = (p0 - c.o).len2(), r = c.r;
        double d = x - r * r;
        vector<Point> ret;
        if(d < -eps){
            return ret;
        }
        if(d < 0){
            d = 0;
        }
        Point p = (p0 - c.o) * (r * r / x), delta = ((p0 - c.o) * (-r * sqrt(d) / x)).turn90();
        ret.push_back(c.o + p + delta);
        ret.push_back(c.o + p - delta);
        return ret;
    }
    
    double TH(double x)
    {
        return x * PI / 180;
    }
    
    int sgn(double x)
    {
        if(fabs(x) < eps) return 0;
        return x > 0 ? 1 : -1;
    }
    double L(Point aa, Point bb)
    {
        if(sgn((aa - bb).len2() - 4.0 * r * r) == 0){
            return PI * r;
        }
        Point cc = {0, 0};
        double a = (bb - cc).len(), b = (aa - cc).len(), c = (aa - bb).len();
        double cosc = (b * b + a * a - c * c) / (2 * a * b);
        double th = acos(cosc);
        return th * r;
    }
    
    double val(int n)
    {
        //printf("%d
    ", n);
        Point o = {0, 0};
        Point p = {0, -R}; Point pp = p;
        p = p.rotate(TH(1.0 * n / 1000));
        double dist = (pp - p).len();
        if(dist <= sqrt(R * R - r * r) * 2){
            return dist;
        }
        Circle c; c.o = {0, 0}; c.r = r;
        vector<Point> inter = circleTangentPoint(c, p);
        vector<Point> origi = circleTangentPoint(c, pp);
        Point p1 = inter[0], p2 = inter[1], p3 = origi[0], p4 = origi[1];
        double ans = min(min(L(p1, p3), L(p1, p4)), min(L(p2, p3), L(p2, p4)));
        return ans + 2 * (p - p1).len();
    }
    
    void build(int o, int l, int r)
    {
        v[o].clear();
        if(l == r)return;
        build(lson);
        build(rson);
    }
    void update(int o, int l, int r)
    {
        if(LL <= l && r <= RR)
        {
            v[o].push_back(X);
            return;
        }
        if(LL <= mid)update(lson);
        if(RR > mid)update(rson);
    }
    set<int>sot;
    const int A = 360000;
    const int H = 180000;
    double ans[N];
    int minn(int x)
    {
        if(x<0)x=-x;
        x %= A;
        x += A;
        x %= A;
        return min(x, A - x);
    }
    void solve(int o, int l, int r, int maxD)
    {
        for(auto x : v[o])
        {
            set<int>::iterator it = sot.lower_bound(x + H);
            if(it != sot.end())gmax(maxD, minn(x + A - *it));
            if(it != sot.begin())gmax(maxD, minn(*(--it) - x));
            sot.insert(x);
            sot.insert(x + A);
        }
        if(l == r)
        {
            ans[l] = val(maxD);
        }
        else
        {
            solve(lson, maxD);
            solve(rson, maxD);
        }
        for(auto x : v[o])
        {
            sot.erase(x);
            sot.erase(x + A);
        }
        v[o].clear();
    }
    int main()
    {
        while(~scanf("%lf%lf", &R, &r))
        {
            scanf("%d", &n);
            for(int i = 1; i <= n; ++i)
            {
                scanf("%d", &a[i]);
                w[a[i]].push_back(1);
            }
            int Q;
            scanf("%d", &Q);
            build(rt);
            for(int i = 1; i <= Q; ++i)
            {
                int op, x;
                scanf("%d%d", &op, &x);
                w[x].push_back(i + 1);
            }
            for(int i = 0; i < 360000; ++i)
            {
                X = i;
                for(int j = 0; j < w[i].size(); j += 2)
                {
                    LL = w[i][j];
                    if(j == w[i].size() - 1)RR = Q + 1;
                    else RR = w[i][j + 1] - 1;
                    update(rt);
                }
                w[i].clear();
            }
            solve(rt, 0);
            for(int i = 1; i <= Q + 1; ++i)printf("%.10f
    ", ans[i]);
        }
        return 0;
    }
    
    /*
    
     题意:
    10 5
    2
    0 90000
    4
    1 180000
    1 240000
    2 0
    2 90000
    
    
     类型:
    
     分析:
    
     优化:
    
     trick:
    
     数据:
    
     Sample Input
    
     Sample Output
    
    
     */
    

      

    F. Computing MDSST

    设$f[S][i]$表示$S$集合的点形成一棵树,根为$i$的最小代价,枚举补集的子集转移。

    时间复杂度$O(3^nn^2)$。

    #include<cstdio>
    typedef long long ll;
    const int N=15;
    const ll inf=1LL<<60;
    int n,i,j,S,U,T,c[1<<N],g[N][N];ll f[1<<N][N];
    inline void up(ll&a,ll b){a>b?(a=b):0;}
    int main(){
    	scanf("%d",&n);
    	for(i=0;i<n;i++)for(j=i+1;j<n;j++){
    		scanf("%d",&g[i][j]);
    		g[j][i]=g[i][j];
    	}
    	for(S=0;S<1<<n;S++)for(i=0;i<n;i++)f[S][i]=inf;
    	for(i=0;i<1<<n;i++)c[i]=__builtin_popcount(i);
    	for(i=0;i<n;i++)f[1<<i][i]=0;
    	for(S=0;S<1<<n;S++)for(i=0;i<n;i++)if(S>>i&1){
    		for(j=0;j<n;j++)if(j!=i&&(S>>j&1)){
    			T=S^(1<<i)^(1<<j);
    			for(U=T;;U=(U-1)&T){
    				up(f[S][i],f[(T-U)|(1<<i)][i]+f[U|(1<<j)][j]+1LL*g[i][j]*(c[U]+1)*(n-c[U]-1));
    				if(!U)break;
    			}
    		}
    	}
    	for(i=1;i<n;i++)up(f[(1<<n)-1][0],f[(1<<n)-1][i]);
    	printf("%lld",f[(1<<n)-1][0]);
    }
    

      

    G. MST with Metropolis

    首先求出最小生成树,那么对于每个点可以看成加入$deg_i$条边权为$0$的边,LCT维护即可。

    时间复杂度$O(mlog m)$。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int N=1000000;
    struct edge{int x,y,a;}e[N];
    bool cmp(const edge&a,const edge&b){return a.a<b.a;}
    int n,m,i,j,fa[N];
    int f[N],son[N][2],val[N],sum[N],from[N],tmp[N];bool rev[N];
    vector<int>vg[N];
    ll all;
    int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
    inline bool isroot(int x){return !f[x]||(son[f[x]][0]!=x&&son[f[x]][1]!=x);}
    inline void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
    inline void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}
    inline void up(int x){
      sum[x]=val[x],from[x]=x;
      if(son[x][0])if(sum[son[x][0]]>sum[x])sum[x]=sum[son[x][0]],from[x]=from[son[x][0]];
      if(son[x][1])if(sum[son[x][1]]>sum[x])sum[x]=sum[son[x][1]],from[x]=from[son[x][1]];
    }
    inline void rotate(int x){
      int y=f[x],w=son[y][1]==x;
      son[y][w]=son[x][w^1];
      if(son[x][w^1])f[son[x][w^1]]=y;
      if(f[y]){
        int z=f[y];
        if(son[z][0]==y)son[z][0]=x;
        if(son[z][1]==y)son[z][1]=x;
      }
      f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
    }
    inline void splay(int x){
      int s=1,i=x,y;tmp[1]=i;
      while(!isroot(i))tmp[++s]=i=f[i];
      while(s)pb(tmp[s--]);
      while(!isroot(x)){
        y=f[x];
        if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
      up(x);
    }
    inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
    inline void makeroot(int x){access(x);splay(x);rev1(x);}
    inline void link(int x,int y){makeroot(x);f[x]=y;access(x);}
    inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}
    inline void cut(int x,int y){makeroot(x);cutf(y);}
    inline int askfrom(int x,int y){makeroot(x);access(y);splay(y);return from[y];}
    inline ll solve(int x){
      ll sum=0;
      vector<int>v;
      for(int i=0;i<vg[x].size();i++){
        int k=vg[x][i];
        sum+=e[k].a;
        int A=x,B=e[k].x+e[k].y-A;
        int j=askfrom(A,B);
        sum-=e[j-n].a;
        v.push_back(j);
        cut(j,e[j-n].x),cut(j,e[j-n].y);
        link(A,n+m+k),link(B,n+m+k);
      }
      for(int i=0;i<vg[x].size();i++){
        int k=vg[x][i];
        int A=x,B=e[k].x+e[k].y-A;
        cut(A,n+m+k),cut(B,n+m+k);
      }
      for(int i=0;i<v.size();i++){
        int j=v[i];
        link(j,e[j-n].x),link(j,e[j-n].y);
      }
      return sum+all;
    }
    int main(){
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].a);
      sort(e+1,e+m+1,cmp);
      for(i=1;i<=n;i++)fa[i]=i,val[i]=-1,from[i]=i;
      for(i=1;i<=m;i++)val[n+i]=e[i].a,from[n+i]=n+i;
      for(i=1;i<=m;i++)val[n+m+i]=0,from[n+m+i]=n+m+i;
      for(i=1;i<=m;i++)if(F(e[i].x)!=F(e[i].y)){
        fa[fa[e[i].x]]=fa[e[i].y];
        link(e[i].x,n+i);
        link(e[i].y,n+i);
        all+=e[i].a;
      }
      for(i=1;i<=m;i++)vg[e[i].x].push_back(i),vg[e[i].y].push_back(i);
      for(i=1;i<=n;i++)printf("%lld
    ",solve(i));
    }
    

      

    H. Number of Cycles

    留坑。

    I. Sum of Squares of the Occurrence Counts

    建立后缀自动机,设$w_i=ml_i-ml_{pre_i},v_i$表示$i$点的$right$集合大小,则$ans=sum w_iv_i^2$。

    每次加入一个新点时,需要将该点到根路径上所有$v$值加$1$,LCT打标记维护即可。

    时间复杂度$O(nlog n)$。

    #include<cstdio>
    #include<cstring>
    #define N 200010
    typedef long long ll;
    char s[N];int n,i;ll ans;
    int tot=1,last=1,pre[N],son[N][26],ml[N];
    namespace LCT{
    int f[N],son[N][2],a[N];
    ll tag[N];
    bool rev[N];
    ll w[N],v[N],sw[N],swv[N];
    inline void swap(int&a,int&b){int c=a;a=b;b=c;}
    inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
    inline void reverse(int x){if(x)swap(son[x][0],son[x][1]),rev[x]^=1;}
    inline void add(int x,ll y){
      if(x){
        v[x]+=y;
        swv[x]+=sw[x]*y;
        tag[x]+=y;
      }
    }
    inline void up(int x){
      sw[x]=w[x]+sw[son[x][0]]+sw[son[x][1]];
      swv[x]=w[x]*v[x]+swv[son[x][0]]+swv[son[x][1]];
    }
    inline void pb(int x){
      if(rev[x])reverse(son[x][0]),reverse(son[x][1]),rev[x]=0;
      if(tag[x])add(son[x][0],tag[x]),add(son[x][1],tag[x]),tag[x]=0;
    }
    inline void rotate(int x){
      int y=f[x],w=son[y][1]==x;
      son[y][w]=son[x][w^1];
      if(son[x][w^1])f[son[x][w^1]]=y;
      if(f[y]){
        int z=f[y];
        if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
      }
      f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y);
    }
    inline void splay(int x){
      int s=1,i=x,y;a[1]=i;
      while(!isroot(i))a[++s]=i=f[i];
      while(s)pb(a[s--]);
      while(!isroot(x)){
        y=f[x];
        if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
      up(x);
    }
    inline void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
    inline void makeroot(int x){access(x);splay(x);reverse(x);}
    inline void link(int x,int y){makeroot(x);f[x]=y;access(x);}
    inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;}
    inline void cut(int x,int y){makeroot(x);cutf(y);}
    inline void changew(int x,ll p){
      access(x);
      splay(x);
      w[x]=p;
      up(x);
    }
    inline void maketag(int x){
      makeroot(1);
      access(x);
      splay(x);
      ans+=2*swv[x]+sw[x];
      add(x,1);
    }
    inline void copy(int y,int x){
      access(x);splay(x);
      w[y]=w[x];
      v[y]=v[x];
      up(y);
    }
    inline void setv(int x,int p){
      w[x]=p;
      up(x);
    }
    }
    inline void add(int w){
      int p=++tot,x=last,r,q;
      ml[p]=ml[x]+1;last=p;
      for(;x&&!son[x][w];x=pre[x])son[x][w]=p;
      if(!x){
        pre[p]=1;
        LCT::setv(p,ml[p]-ml[pre[p]]);
        LCT::link(p,pre[p]);
      }else if(ml[x]+1==ml[q=son[x][w]]){
        pre[p]=q;
        LCT::setv(p,ml[p]-ml[pre[p]]);
        LCT::link(p,pre[p]);
      }else{
        pre[r=++tot]=pre[q];
        LCT::copy(r,q);
        LCT::link(r,pre[q]);
        memcpy(son[r],son[q],sizeof son[r]);
        ml[r]=ml[x]+1;
        LCT::cut(q,pre[q]);
        LCT::link(q,r);
        pre[p]=pre[q]=r;
        LCT::setv(p,ml[p]-ml[pre[p]]);
        LCT::link(p,r);
        LCT::changew(r,ml[r]-ml[pre[r]]);
        LCT::changew(q,ml[q]-ml[pre[q]]);
        for(;x&&son[x][w]==q;x=pre[x])son[x][w]=r;
      }
      LCT::maketag(p);
    }
    int main(){
      scanf("%s",s+1);n=strlen(s+1);
      for(i=1;i<=n;i++){
        add(s[i]-'a');
        printf("%lld
    ",ans);
      }
    }
    

      

    J. Game of Sorting

    对于一个区间$[l,r]$,若它是单调的,则显然先手必败。

    若去掉$l$或者$r$后变成了单调的,则显然先手必胜。

    若$[l+1,r-1]$是单调的,那么同理先手必败。

    若$[l,r-2]$是单调的,那么先手若取$r$会导致后手必胜,后手同理,故两人会一直取$l$直到出现上面第一种或者第二种情况,可以根据奇偶性判断。

    同理可以得出$[l+2,r]$是单调的情形的处理方法。

    除此之外,有$[l,r]$的答案等于$[l+1,r-1]$的答案,二分找到最小的$k$满足$[l+k,r-k]$可以由上面方法直接判断出胜负即可。

    时间复杂度$O(mlog n)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=1000010;
    int n,i,a[N],fl[N],fr[N],gl[N],gr[N],m,x,y;
    inline int check(int l,int r){
      if(l>=r)return -1;
      if(fr[l]>=r)return -1;
      if(fr[l]==r-1)return 1;
      if(fl[r]==l+1)return 1;
      if(fr[l+1]==r-1)return -1;
      int x;
      if(fr[l]==r-2){
        if(fl[r-1]<fl[r])x=(l&1)^(fl[r-1]&1)^1;
        else x=(l&1)^(fl[r]&1);
        return x?1:-1;
      }
      if(fl[r]==l+2){
        if(fr[l+1]>fr[l])x=(r&1)^(fr[l+1]&1)^1;
        else x=(r&1)^(fr[l]&1);
        return x?1:-1;
      }
      return 0;
    }
    inline int cal(int x,int y){
      int l=0,r=(y-x)/2+5,mid,t,o;
      while(l<=r){
        mid=(l+r)>>1;
        t=check(x+mid,y-mid);
        if(!t)l=mid+1;else r=mid-1,o=t;
      }
      return o;
    }
    int main(){
      scanf("%d",&n);
      for(i=1;i<=n;i++)scanf("%d",&a[i]);
      for(fr[n]=gr[n]=n,i=n-1;i;i--){
        fr[i]=a[i]<=a[i+1]?fr[i+1]:i;
        gr[i]=a[i]>=a[i+1]?gr[i+1]:i;
      }
      for(fl[1]=gl[1]=1,i=2;i<=n;i++){
        fl[i]=a[i]<=a[i-1]?fl[i-1]:i;
        gl[i]=a[i]>=a[i-1]?gl[i-1]:i;
      }
      for(i=1;i<=n;i++)fl[i]=min(fl[i],gl[i]),fr[i]=max(fr[i],gr[i]);
      scanf("%d",&m);
      while(m--)scanf("%d%d",&x,&y),puts(cal(x,y)>0?"Alice":"Bob");
    }
    

      

    K. Subsequence Queries

    设$f_i$表示以字符$i$为结尾的本质不同子序列的个数,$sum$为所有本质不同子序列(包含空串)的个数,则一开始$f_i=0,sum=1$。

    若往序列末尾添加一个字符$x$,则有$f_x=sum,sum=2sum-f_x$,可以将其写成转移矩阵$G_x$。

    考虑将上述式子倒过来,则可以得出删除末尾字符$x$的转移,也就是$G_x^{-1}$。

    则区间$[l,r]$的答案$=G_rG_{r-1}...G_{l+1}G_l=G_{r+1}^{-1}G_{r+2}^{-1}G_{n-1}^{-1}G_n^{-1}G_nG_{n-1}...G_{l+1}G_l$。

    故预处理出$G$的后缀积的最后一列以及$G^{-1}$的后缀积的最后一行即可在$O(S)$的时间里求出$sum$。

    对于预处理,注意到$G$和$G^{-1}$与单位矩阵$E$相比只有$4$个位置不同,故可以只考虑这$4$个位置的线性贡献在$O(S)$的时间里完成矩阵乘法。

    时间复杂度$O((n+q)S)$。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define rep(i) for(int i=0;i<M;i++)
    using namespace std;
    const int N=1000010,M=53,P=1000000007;
    int n,i,j,g[M][M],w[M][M],tmp[M],b[N][M],c[N][M];char a[N];
    inline int getid(char x){
    	if(x>='a'&&x<='z')return x-'a';
    	return x-'A'+26;
    }
    inline void apply(int x){
    	//x,x,-1
    	//x,M-1,1
    	//M-1,x,-1
    	//M-1,M-1 1
    	rep(i)w[i][x]=g[i][x],w[i][M-1]=g[i][M-1];
    	rep(i){
    	 	(g[i][x]-=w[i][x])%=P;
    	 	(g[i][M-1]+=w[i][x])%=P;
    	 	(g[i][x]-=w[i][M-1])%=P;
    	 	(g[i][M-1]+=w[i][M-1])%=P;
    	}
    }
    inline void applyinv(int x){
    	rep(i)tmp[i]=g[x][i],g[x][i]=(2LL*g[x][i]-g[M-1][i])%P;
    	rep(i)g[M-1][i]=tmp[i];
    	/*newf[x]=olds
    	news=olds*2-oldf[x]
    	
    	olds=newf[x]
    	oldf[x]=newf[x]*2-news*/
    }
    inline int cal(int l,int r){
    	int ret=0;
    	rep(i)ret=(1LL*b[l][i]*c[r+1][i]+ret)%P;
    	return (ret+P)%P;
    }
    const int Base=1000000000;
    int len[M+1];
    int num[M+1][N];
    inline void copy(int x,int y){
    	len[x]=len[y];
    	for(int i=len[x];i;i--)num[x][i]=num[y][i];
    }
    inline void mul2(int x){
    	int l=len[x],i;
    	num[x][++l]=0;
    	for(i=1;i<=l;i++)num[x][i]<<=1;
    	for(i=1;i<l;i++)if(num[x][i]>=Base)num[x][i+1]++,num[x][i]-=Base;
    	while(l>1&&!num[x][l])l--;
    	len[x]=l;
    }
    inline void sub(int x,int y){
    	int l=len[x],i;
    	for(i=len[y];i;i--)num[x][i]-=num[y][i];
    	for(i=1;i<l;i++)if(num[x][i]<0)num[x][i+1]--,num[x][i]+=Base;
    	while(l>1&&!num[x][l])l--;
    	len[x]=l;
    }
    inline void gao(int x){
    	copy(M,x);
    	copy(x,M-1);
    	mul2(M-1);
    	sub(M-1,M);
    }
    void write(int x){
    	printf("%d",num[x][len[x]]);
    	for(int i=len[x]-1;i;i--)printf("%09d",num[x][i]);
    }
    int main(){
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	rep(i)g[i][i]=1;
    	rep(j)b[n+1][j]=g[j][M-1];
    	for(i=n;i;i--){
    		apply(getid(a[i]));
    		rep(j)b[i][j]=g[j][M-1];
    	}
    	rep(i)rep(j)g[i][j]=0;
    	rep(i)g[i][i]=1;
    	rep(j)c[n+1][j]=g[M-1][j];
    	for(i=n;i;i--){
    		applyinv(getid(a[i]));
    		rep(j)c[i][j]=g[M-1][j];
    	}
    	/*int x,y;
    	while(~scanf("%d%d",&x,&y)){
    		printf("%d
    ",cal(x,y));
    	}*/
    	int q,a0,b0,pp,qq,rr,last=0;
    	int L,R;
    	scanf("%d%d%d%d%d%d",&q,&a0,&b0,&pp,&qq,&rr);
    	while(q--){
    		int na=(1LL*pp*a0+1LL*qq*b0+last+rr)%P;
    		int nb=(1LL*pp*b0+1LL*qq*a0+last+rr)%P;
    		int x=min(na%n+1,nb%n+1);
    		int y=max(na%n+1,nb%n+1);
    		L=x,R=y;
    		last=cal(x,y);
    		a0=na,b0=nb;
    	}
    	printf("%d",last);
    	return 0;
    	rep(i)len[i]=1;
    	num[M-1][1]=1;
    	for(i=L;i<=R;i++)gao(getid(a[i]));
    	write(M-1);
    }
    /*
    aadhuihGDSTYFSJHJUYFRgdgjesfgAGFDHSFHDTedsjydaJdgHSdfhyjFhsGvfhdzgfjsfjySfgyjhzdfgjzdfgjzfgjhdfgjGfyjhzdgfzjyfgzdjhgfdjdfdfdfdfdfdfdfdfdffdfdfzgjSGHFDsyJHFGhGFujyFGTjySFyJGDjSdgjyhSFhgZFGjhSDF
    100 100 245 463 356 234243
    85192723079788
    
    */
    

      

    L. XOR Transformation

    将$T$二进制拆分,将每个$1$拿出来单独做$2^t$步操作。

    对于$2^t$步操作,每个点的值会变成往后$2^t$一步$k$个点的异或和,将$k$模以两倍的环长后用前缀异或和计算即可。

    时间复杂度$O(nlog T)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=222222;
    int n,m,i,a[N];ll T;
    int v[N],q[N],b[N];
    void solve(int k){
    	ll t=1LL<<k;
    	t%=n;
    	int i,j;
    	for(i=0;i<n;i++)v[i]=0;
    	for(i=0;i<n;i++)if(!v[i]){
    		int len=0;
    		for(j=i;!v[j];j=(j+t)%n)v[q[len++]=j]=1;
    		for(j=0;j<len;j++)b[j]=b[j+len]=a[q[j]];
    		for(j=1;j<len+len;j++)b[j]^=b[j-1];
    		for(j=0;j<len;j++){
    			int val=b[((j+m-1)%(len*2)+len*2)%(len*2)];
    			if(j)val^=b[j-1];
    			a[q[j]]=val;
    		}
    	}
    }
    int main(){
    	scanf("%d%d%lld",&n,&m,&T);
    	for(i=0;i<n;i++)scanf("%d",&a[i]);
    	for(i=0;i<62;i++)if(T>>i&1)solve(i);
    	for(i=0;i<n;i++)printf("%d ",a[i]);
    }
    

      

  • 相关阅读:
    拖拽文件上传demo
    JS权限树数据处理demo
    某面试题 a==1&&a==2&&a==3 的解决方案以及涉及知识
    解决forEach函数中异步调用及Promise.all()的基础使用
    基于element ui的el-date-picker 日、周、月粒度切换时间选择器
    基于element ui的el-table-column行内编辑input/select封装
    JavaScript优化技术
    vue-canvas-poster生成海报 jsZip打包称压缩包
    uniapp中使用uView时 TypeError: Cannot read property ‘mark‘ of undefined
    JS中深拷贝数组、对象、对象数组方法
  • 原文地址:https://www.cnblogs.com/clrs97/p/8711574.html
Copyright © 2020-2023  润新知