zoukankan      html  css  js  c++  java
  • XVII Open Cup named after E.V. Pankratiev. GP of Moscow Workshops

    A. Centroid Tree

    枚举至多两个重心作为根,检查对于每个点是否都满足$2size[x]leq size[father[x]]$即可。

    #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() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
    #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 = 1e5 + 10, 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, m;
    vector<int>a[N];
    int root;
    int treesz;
    int sz[N];
    int mxp[N];
    bool done[N];
    int v[N];
    bool FLAG;
    
    vector<int>vt;
    int getsz(int x, int fa)
    {
    	sz[x] = 1;
    	for (auto y : a[x])if (y != fa && !done[y])
    	{
    		sz[x] += getsz(y, x);
    	}
    	return sz[x];
    }
    void getroot(int x, int fa)
    {
    	mxp[x] = treesz - sz[x];// root = 0;
    	for (auto y : a[x])if (y != fa && !done[y])
    	{
    		getroot(y, x);
    		gmax(mxp[x], sz[y]);
    	}
    	if (mxp[x] < mxp[root])
    	{
    		root = x;
    		vt.clear(); vt.push_back(x);
    	}
    	else if (mxp[x] == mxp[root])
    	{
    		vt.push_back(x);
    	}
    }
    
    bool check(int x, int fa)
    {
    	sz[x] = 1;
    	for (auto y : a[x])
    	{
    		if (y == fa)continue;
    		if (!check(y, x))return 0;
    		sz[x] += sz[y];
    	}
    
    	for (auto y : a[x])
    	{
    		if (y == fa)continue;
    		if (sz[y] * 2 > sz[x])return 0;
    	}
    	return 1;
    }
    
    bool dfz(int x)
    {
    	vt.clear();
    	treesz = getsz(x, 0);
    	getroot(x, root = 0);
    
    	for (auto y : vt)
    	{
    		if (check(y, 0))return 1;
    	}
    	return 0;
    }
    int main()
    {
    	//fre();
    	mxp[0] = inf;
    	scanf("%d%d", &casenum, &n);
    	for (casei = 1; casei <= casenum; ++casei)
    	{
    		for (int i = 1; i <= n; ++i)
    		{
    			done[i] = 0;
    			a[i].clear();
    		}
    		for (int i = 1; i < n; ++i)
    		{
    			int x, y;
    			scanf("%d%d", &x, &y);
    			a[x].push_back(y);
    			a[y].push_back(x);
    		}
    
    		puts(dfz(1) ? "Centroid" : "Random");
    
    	}
    	return 0;
    }
    /*
    
    2 7
    1 2
    2 3
    3 4
    4 5
    5 6
    6 7
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    
    1 7
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    
    
    1 4
    1 2
    2 3
    3 4
    */
    

      

    B. Completely Multiplicative Function

    爆搜每个质数是$1$还是$-1$,加上前$n$项的前缀和的绝对值必须小于$log n$的剪枝即可通过。

    更好的做法:对于质数$p$,若$pmod 3=1$,则填$1$,否则填$-1$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 1e6 + 10;
    char mu[N] =
    {
    	0,1,1,-1,1,1,-1,-1,1,1,1,-1,-1,1,-1,-1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,-1,1,-1,1,1,1,1,-1,1,-1,-1,-1,1,1,1,-1,-1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,-1,-1,1,1,-1,-1,-1,1,-1,-1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,-1,-1,1,-1,-1,1,1,-1,1,1,-1,1,1,1,-1,1,-1,-1,-1,1,-1,-1,1,-1,1,1,1,-1,-1,1,-1,-1,1,1,-1,-1,1,1,1,-1,1,1,-1,-1,1,1,1,-1,-1,-1,-1,-1,1,1,1,-1,-1,1,-1,-1,-1,1,1,1,-1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,1,1,1,-1,1,-1,-1,-1,-1,1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,1,1,1,-1,-1,1,1,-1,1,1,1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,1,1,1,-1,1,-1,1,1,-1,-1,-1,1,-1,1,1,1,1,-1,1,-1,1,1,-1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,-1,1,-1,1,1,1,1,-1,-1,1,-1,1,-1,-1,1,-1,-1,1,1,1,-1,1,1,-1,1,-1,1,-1,-1,-1,1,-1,-1,1,1,1,-1,1,-1,-1,1,-1,1,1,-1,-1,1,-1,-1,-1,-1,1,1,1,-1,1,1,-1,1,-1,-1,-1,1,1,-1,1,-1,1,-1,1,1,-1,1,1,-1,1,1,-1,-1,-1,-1,1,-1,1,1,1,-1,-1,-1,-1,1,1,1,-1,1,-1,-1,-1,1,-1,-1,1,1,1,-1,1,1,1,-1,-1,1,1,1,-1,1,-1,1,-1,-1,-1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,-1,1,1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,1,1,-1,1,-1,-1,1,-1,1,-1,-1,-1,1,1,1,-1,1,-1,-1,1,-1,1,1,1,1,1,-1,1,-1,1,-1,-1,-1,1,-1,-1,-1,1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,-1,1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,1,1,1,1,1,1,-1,-1,-1,1,1,-1,-1,1,-1,1,1,-1,1,-1,1,1,-1,-1,1,-1,-1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,1,1,-1,1,1,-1,1,-1,1,-1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,-1,1,-1,-1,1,-1,-1,1,-1,-1,1,-1,1,1,1,-1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,1,1,1,-1,-1,-1,-1,1,1,1,-1,1,1,-1,1,1,1,-1,1,-1,-1,1,1,-1,-1,1,-1,1,1,-1,1,-1,1,1,-1,-1,1,-1,1,-1,1,-1,1,1,-1,1,-1,1,-1,-1,-1,1,1,1,-1,-1,1,1,-1,-1,-1,-1,1,-1,1,1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,-1,1,1,-1,-1,1,-1,1,1,-1,1,1,-1,1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,-1,-1,1,1,1,-1,1,-1,-1,1,-1,1,-1,1,-1,-1,1,-1,1,1,1,-1,-1,1,1,1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,-1,1,-1,1,-1,1,-1,-1,1,1,-1,1,-1,1,1,-1,1,-1,1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,-1,1,1,-1,-1,-1,-1,1,1,1,1,-1,1,-1,-1,1,1,1,-1,-1,1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,1,-1,1,-1,1,-1,-1,-1,1,-1,1,-1,1,1,1,-1,-1,1,1,1,-1,1,-1,1,-1,-1,1,1,-1,-1,1,-1,-1,1,1
    };
    int f[N];
    int first[N];
    int fac[N];
    int prim[N], pnum;
    int n;
    int lg2[N];
    
    void check()
    {
    	for (int i = 1; i <= n; i++) f[i] = f[i - 1] + mu[i];
    	for (int i = 1; i <= n; i++)if (abs(f[i]) > 20)
    	{
    		printf("f[%d] = %d
    ", i, f[i]);
    		while (1);
    	}
    	for (int i = 1; i <= n; ++i)
    	{
    		for (int j = 1; i * j <= n; ++j)
    		{
    			if (mu[i * j] != mu[i] * mu[j])
    			{
    				printf("%d %d %d %d %d %d
    ", i, j, i *j, mu[i], mu[j], mu[i * j]);
    				puts("ERROR");
    				while (1);
    			}
    		}
    	}
    }
    
    bool FLAG;
    inline char abs(char x) { return x > 0 ? x : -x; }
    void dfs(int x,char y)
    {
    	if (x > n)
    	{
    		//puts("YES!");
    		FLAG = 1;
    		return;
    	}
    	while (fac[x])
    	{
    		mu[x] = mu[fac[x]] * mu[first[x]];
    		y+=mu[x];
    		if (abs(y) > lg2[x])return;
    		++x;
    	}
    	if (x > n)
    	{
    		//puts("YES!");
    		FLAG = 1;
    		return;
    	}
    	{
    		mu[x] = 1;
    		y++;
    		if (abs(y) <= lg2[x])
    		{
    			dfs(x + 1,y);
    		}
    
    		if (FLAG)return;
    		mu[x] = -1;
    		y -= 2;
    		if (abs(y) <= lg2[x])
    		{
    			dfs(x + 1,y);
    		}
    	}
    }
    
    void getprime()
    {
    	fac[1] = 1;
    	for (int i = 2; i < N; i++)
    	{
    		if (fac[i])continue;
    		prim[pnum++] = i;
    		for (int j = i + i; j < N; j += i)
    		{
    			fac[j] = i;
    		}
    	}
    }
    
    
    
    int main()
    {
    	getprime();
    	//printf("%d
    ", pnum);
    
    	n = 1e6; fac[n + 1] = 0;
    	lg2[1] = 1;
    	for (int i = 2; i <= n; ++i)
    	{
    		lg2[i] = lg2[i / 2] + 1;
    		if (fac[i])
    		{
    			first[i] = i / fac[i];
    		}
    	}
    
    	for (int i = 1; i <= 820; ++i)f[i] = f[i - 1] + mu[i];
    	dfs(821,f[820]);
    	//check();
    
    	//for (int i = 1; i <= 3000; i++) printf("%d,", mu[i]);
    
    	scanf("%d", &n);
    	//n = 10;
    	//for (int i = 1; i <= n; i++)if(!fac[i]) printf("%d %d
    ", i,mu[i]);
    	for (int i = 1; i <= n; i++)printf("%d%c", mu[i], i == n ? '
    ' : ' ');
    
    
    	return 0;
    }
    

      

    C. Even and Odd

    求出DFS生成树,只保留树边。

    对于每个基环,若它是奇环,那么上面的树边都不能保留;若它是偶环,那么若它与某个奇环相交,将会得到更大的奇环,这些边也不能保留。

    用并查集维护每个点向上第一条未删去的树边,树状数组判断路径上是否存在奇环,迭代删除$O(log n)$轮即可。如果直接用并查集维护有交的树边集合,那么只要集合内存在基本奇环则要删除,可以做到更优秀的复杂度。

    预处理结束后,对于每个连通块,当成树统计答案即可。

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

    #include<cstdio>
    const int N=200010,M=400010;
    int n,m,i,x,y,g[N],v[M],nxt[M],ed;
    int d[N],f[N],vis[N],dfn;
    int fa[N],c[N][2];
    int dep[N],gg[N];
    int q[N],V[M],NXT[M],ED;
    int st[N],en[N],lim,bit[M];
    long long ans[2];
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    int G(int x){return gg[x]==x?x:gg[x]=G(gg[x]);}
    inline void ADD(int x,int y){V[++ED]=y;NXT[ED]=q[x];q[x]=ED;}
    inline void modify(int x,int p){for(;x<=lim;x+=x&-x)bit[x]+=p;}
    inline int ask(int x){int t=0;for(;x;x-=x&-x)t+=bit[x];return t;}
    inline void go(int x,int y){
        //printf("go %d %d
    ",x,y);
        while(1){
            x=G(x);
            if(dep[x]<=dep[y])return;
            //printf("del %d
    ",x);
            modify(st[x],1);
            modify(en[x],-1);
            gg[x]=f[x];
        }
    }
    void dfs1(int x,int y){
        f[x]=y;
        vis[x]=++dfn;
        d[x]=d[y]^1;
        dep[x]=dep[y]+1;
        gg[x]=x;
        st[x]=++lim;
        for(int i=g[x];i;i=nxt[i]){
            int u=v[i];
            if(u==y)continue;
            if(!vis[u]){
                //printf("%d->%d
    ",x,u);
                dfs1(u,x);
            }
        }
        en[x]=++lim;
    }
    void dfs2(int x,int y){
        vis[x]=++dfn;
        for(int i=g[x];i;i=nxt[i]){
            int u=v[i];
            if(u==y)continue;
            if(!vis[u]){
                dfs2(u,x);
            }else if(vis[u]<vis[x]){
                if(d[u]==d[x]){
                    //printf("odd %d %d
    ",x,u);
                    go(x,u);
                }else{
                    ADD(u,x);
                }
            }
        }
        for(int i=q[x];i;i=NXT[i]){
            int u=V[i];
            //printf("even %d %d asku=%d askx=%d
    ",u,x,ask(st[u]),ask(st[x]));
            if(ask(st[u])>ask(st[x]))go(u,x);
        }    
    }
    int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
    inline void merge(int x,int y){
        //printf("merge %d %d
    ",x,y);
        x=F(x),y=F(y);
        fa[x]=y;
        ans[0]+=1LL*c[x][0]*c[y][0];
        ans[0]+=1LL*c[x][1]*c[y][1];
        ans[1]+=1LL*c[x][0]*c[y][1];
        ans[1]+=1LL*c[x][1]*c[y][0];
        c[y][0]+=c[x][0];
        c[y][1]+=c[x][1];
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            add(x,y),add(y,x);
        }
        dfs1(1,0);
        for(i=1;i<=n;i++)vis[i]=0;
        for(int _=10;_;_--){
            for(i=1;i<=n;i++)vis[i]=q[i]=0;
            dfn=ED=0;
            dfs2(1,0);
        }
        for(i=1;i<=n;i++)fa[i]=i,c[i][d[i]]=1;
        for(i=2;i<=n;i++)if(gg[i]==i)merge(i,f[i]);
        printf("%lld %lld",ans[0],ans[1]);
    }
    /*
    4 3
    1 2
    1 3
    1 4
    
    
    4 4
    1 2
    2 3
    3 4
    4 2
    
    
    5 6
    1 2
    2 3
    3 4
    4 5
    1 4
    3 5
    
    4 5
    1 2
    1 3
    2 4
    3 4
    2 3
    
    
    6 8
    1 2
    1 3
    2 4
    3 4
    3 5
    4 5
    4 6
    5 6
    */
    

      

    D. Great Again

    设$f[i]$表示前$i$个人分组的最大得分,枚举当前段的得分,线段树优化转移即可。

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

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<set>
    using namespace std;
    const int N=300010,M=2222222;
    int n,m,j,L,R,i,lim,tmp,a[N],f[N];
    int v[M];
    multiset<int>T[N*2];
    void build(int x,int a,int b){
        v[x]=-M;
        if(a==b)return;
        int mid=(a+b)>>1;
        build(x<<1,a,mid),build(x<<1|1,mid+1,b);
    }
    inline void up(int x){v[x]=max(v[x<<1],v[x<<1|1]);}
    void ins(int x,int a,int b,int c,int p){
        if(a==b){
            T[a].insert(p);
            v[x]=*T[a].rbegin();
            return;
        }
        int mid=(a+b)>>1;
        if(c<=mid)ins(x<<1,a,mid,c,p);
        else ins(x<<1|1,mid+1,b,c,p);
        up(x);
    }
    void del(int x,int a,int b,int c,int p){
        if(a==b){
            T[a].erase(T[a].find(p));
            if(T[a].empty())v[x]=-M;else
            v[x]=*T[a].rbegin();
            return;
        }
        int mid=(a+b)>>1;
        if(c<=mid)del(x<<1,a,mid,c,p);
        else del(x<<1|1,mid+1,b,c,p);
        up(x);
    }
    int ask(int x,int a,int b,int c,int d){
        if(c<=a&&b<=d)return v[x];
        int mid=(a+b)>>1,t=-M;
        if(c<=mid)t=ask(x<<1,a,mid,c,d);
        if(d>mid)t=max(t,ask(x<<1|1,mid+1,b,c,d));
        return t;
    }
    int main(){
        scanf("%d%d%d",&n,&L,&R);
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i]+=a[i-1];
        }
        m=n+n;
        for(i=0;i<=n;i++)a[i]+=n;//0..m
        build(1,0,m);
        for(i=1,j=0;i<=n;i++){
            if(i>=L)ins(1,0,m,a[i-L],f[i-L]);
            if(i-R-1>=0)del(1,0,m,a[i-R-1],f[i-R-1]);
            f[i]=ask(1,0,m,a[i],a[i]);
            if(a[i]>0)f[i]=max(f[i],ask(1,0,m,0,a[i]-1)+1);
            if(a[i]<m)f[i]=max(f[i],ask(1,0,m,a[i]+1,m)-1);
            //printf("f[%d]=%d
    ",i,f[i]);
        }
        if(f[n]<-M/2)puts("Impossible");else printf("%d",f[n]);
    }
    

      

    E. Jumping is Fun

    每个点不管跳多少步,能到达的范围必然是一个区间。

    设$f[i][j]$表示$j$点跳$2^i$步能到的范围,可以用线段树求出。

    从高到低枚举答案的二进制的每一位,利用$f$数组求出范围,然后枚举$x$,判断是否存在$y$满足$x$与$y$都不能相互到达即可。

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

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=200010,M=530000,K=18;
    int n,i,j,x,pre[N],suf[N],ans;
    struct P{
        int x,y;
        P(){}
        P(int _x,int _y){x=_x,y=_y;}
        P operator+(const P&b){return P(min(x,b.x),max(y,b.y));}
    }f[K][N],v[K][M],a[N],b[N];
    void build(int o,int x,int a,int b){
        if(a==b){
            v[o][x]=f[o][a];
            return;
        }
        int mid=(a+b)>>1;
        build(o,x<<1,a,mid),build(o,x<<1|1,mid+1,b);
        v[o][x]=v[o][x<<1]+v[o][x<<1|1];
    }
    P ask(int o,int x,int a,int b,int c,int d){
        if(c<=a&&b<=d)return v[o][x];
        int mid=(a+b)>>1;
        P t(N,1);
        if(c<=mid)t=ask(o,x<<1,a,mid,c,d);
        if(d>mid)t=t+ask(o,x<<1|1,mid+1,b,c,d);
        return t;
    }
    inline P go(int o,P b){
        //if(b.x<1||b.y>n)puts("ERROR");
        return ask(o,1,1,n,b.x,b.y);
    }
    inline bool check(int o){
      //printf("now check %d
    ",o);
        int i;
        for(i=1;i<=n;i++)b[i]=go(o,a[i]);
        pre[0]=N;
        for(i=1;i<=n;i++)pre[i]=min(pre[i-1],b[i].y);
        suf[n+1]=0;
        for(i=n;i;i--)suf[i]=max(suf[i+1],b[i].x);
        for(i=1;i<=n;i++){
            if(pre[b[i].x-1]<i){
                //printf("to pre x=%d pre[%d]=%d
    ",i,b[i].x-1,pre[b[i].x-1]);
                return 1;
            }
            if(suf[b[i].y+1]>i){
                //printf("to suf x=%d
    ",i);
                return 1;
            }
        }
        return 0;
    }
    int main(){
        scanf("%d",&n);
        for(i=1;i<=n;i++){
            scanf("%d",&x);
            f[0][i].x=max(1,i-x);
            f[0][i].y=min(n,i+x);
        }
        build(0,1,1,n);
        for(i=1;i<K;i++){
            for(j=1;j<=n;j++){
                f[i][j]=go(i-1,f[i-1][j]);
                //printf("f[%d][%d]=%d %d
    ",i,j,f[i][j].x,f[i][j].y);
            }
            build(i,1,1,n);
        }
        for(i=1;i<=n;i++){
            a[i]=P(i,i);
            //printf("->%d %d %d
    ",i,a[i].x,a[i].y);
        }
        for(i=K-1;~i;i--){
            if(check(i)){
                //printf("checkok %d
    ",i);
                //for(j=1;j<=n;j++)printf("a[%d]=%d %d
    ",j,a[j].x,a[j].y);
                for(j=1;j<=n;j++)a[j]=b[j];
                //for(j=1;j<=n;j++)printf("b[%d]=%d %d
    ",j,a[j].x,a[j].y);
                ans|=1<<i;
            }
        }
        printf("%d",ans+1);
    }
    /*
    8
    7 1 1 1 1 1 1 7
    
    10
    2 2 1 2 2 1 2 2 1 2
    */
    

      

    F. Online LCS

    将两个串插入同一个后缀自动机,同时维护$v[i][j]$表示节点$i$表示的子串集合是否在串$j$中出现过。

    每次加入新的字符的时候,将对应节点到根路径上所有$v$都标记为$1$,当$v[i][0]$与$v[i][1]$同时为$1$时,可以用它的最大长度去更新最长公共子串的长度。

    注意到每个点在每种串中只需要被标记一次,故发现标记过则退出即可。

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

    #include<cstdio>
    #include<cstring>
    const int N=5000010;//5e6
    int tot=1,last[2]={1,1},pre[N*2],son[N*2][2],ml[N*2];bool v[N*2][2];
    int n,i,ans;long long sum;char a[N];
    inline void extend(int o,int w){
      int p=++tot,x=last[o],r,q;
      for(ml[last[o]=p]=ml[x]+1;x&&!son[x][w];x=pre[x])son[x][w]=p;
      if(!x)pre[p]=1;
      else if(ml[x]+1==ml[q=son[x][w]])pre[p]=q;
      else{
        pre[r=++tot]=pre[q];memcpy(son[r],son[q],sizeof son[r]);
        v[r][0]=v[q][0];
        v[r][1]=v[q][1];
        ml[r]=ml[x]+1;pre[p]=pre[q]=r;
        for(;x&&son[x][w]==q;x=pre[x])son[x][w]=r;
      }
      while(p&&!v[p][o]){
        v[p][o]=1;
        if(v[p][o^1]&&ml[p]>ans)ans=ml[p];
        p=pre[p];
      }
    }
    int main(){
      scanf("%d%s",&n,a);
      for(i=0;i<n;i++){
        extend(((a[i]-'0')^ans)&1,(((a[i]-'0')^ans)/2)&1);
        sum+=ans;
      }
      printf("%lld",sum);
    }
    /*
    5
    0 0
    0 1
    1 0
    1 0
    1 1
    */
    

      

    G. Brawling

    只有左侧朝左的若干人以及右侧朝右的若干人不能保留。

    #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() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
    #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 = 1e6 + 10, 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;
    char s[N];
    int n;
    int solve()
    {
        int l = 1;
        while(l <= n && s[l] != 'R')++l;
    
        int r = n;
        while(r >= 1 && s[r] != 'L')--r;
    
        //a[l] = 'L', a[r] = 'R'
        if(l < r)
        {
            int sub = r - l + 1 - 1;
            return n - sub;
        }
        else
        {
            return n;
        }
    }
    int main()
    {
    	while(~scanf("%s", s + 1))
    	{
    	    n = strlen(s + 1);
            printf("%d
    ", solve());
    	}
    
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    H. I Spy

    随机选择一个点$P=(x,y)$,在附近找一个辅助点$Q=(x+1,y)$。

    因为随机选择,故可以认为对于$P$和$Q$,没有任意两个点离它们的距离相同。

    二分半径求出离$P$和$Q$最近的两个点到它们的距离$R_1,R_2$,得到两个圆,在交点附近检查是否存在点即可。

    如此反复,即可找出所有点的位置。

    #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() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
    #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 = 0, 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;
    LL X0, Y0;
    LL X1, Y1;
    set< pair<LL, LL> >know;
    LL sqr(LL X)
    {
    	return X * X;
    }
    bool IN(LL X0, LL Y0, LL X1, LL Y1, LL R)
    {
    	return sqr(X0 - X1) + sqr(Y0 - Y1) <= R;
    }
    bool check(LL X, LL Y, LL R)
    {
    	printf("? %lld %lld %lld
    ", X, Y, R);
    	fflush(stdout);
    	int num;
    	scanf("%d", &num);
    	for (auto it : know)
    	{
    		if (IN(it.first, it.second, X, Y, R))--num;
    	}
    	return num;
    }
    LL GETR(LL X, LL Y)
    {
    	LL L = 0;
    	LL R = 1e13;
    	while (L < R)
    	{
    		LL MID = (L + R >> 1);
    		if (check(X, Y, MID))R = MID;
    		else L = MID + 1;
    	}
    	return L;
    }
    
    namespace YUAN
    {
    	struct point
    	{
    		double x, y;
    		point() {}
    		point(double a, double b) : x(a), y(b) {}
    		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 double a, const point &b) {
    			return point(a * b.x, a * b.y);
    		}
    		friend point operator / (const point &a, const double &b) {
    			return point(a.x / b, a.y / b);
    		}
    		double norm() {
    			return sqrt(sqr(x) + sqr(y));
    		}
    	};
    
    	point rotate(const point &p, double cost, double sint)
    	{
    		double x = p.x, y = p.y;
    		return point(x * cost - y * sint, x * sint + y * cost);
    	}
    	// 圆与圆求交, ap,bp 两个圆的圆心, ar,br 两个圆的半径。 输出两个交点(要先确认两圆存在交点)
    	pair<point, point> crosspoint(point ap, double ar, point bp, double br)
    	{
    		double d = (ap - bp).norm();
    		double cost = (ar * ar + d * d - br * br) / (2 * ar * d);
    		double sint = sqrt(1. - cost * cost);
    		point v = (bp - ap) / (bp - ap).norm() * ar;
    		return make_pair(ap + rotate(v, cost, -sint), ap + rotate(v, cost, sint));
    	}
    }using namespace YUAN;
    
    void check_ans(LL X, LL Y)
    {
    	for (int i = -2; i <= 2; ++i)
    	{
    		for (int j = -2; j <= 2; ++j)
    		{
    			LL x = X + i;
    			LL y = Y + j;
    			if (abs(x) > 1e6 || abs(y) > 1e6)continue;
    			if (check(x, y, 0))
    			{
    				know.insert({ x,y });
    			}
    		}
    	}
    }
    int main()
    {
    	X0 = rand() * rand() % 900000;
    	Y0 = rand() * rand() % 900000;
    	X1 = X0;
    	Y1 = Y0 + 1;
    
    	scanf("%d", &n);
    	while (know.size() < n)
    	{
    		LL R0 = GETR(X0, Y0);
    		LL R1 = GETR(X1, Y1);
    
    		pair<point, point>ans = crosspoint({ 1.0*X0,1.0*Y0 }, sqrt(R0), { 1.0*X1,1.0*Y1 }, sqrt(R1));
    
    		check_ans(ans.first.x, ans.first.y);
    		check_ans(ans.second.x, ans.second.y);
    	}
    	printf("!");
    	for (auto it : know)
    	{
    		printf(" %lld %lld", it.first, it.second);
    	}
    	puts("");
    	fflush(stdout);
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    【数据】
    
    
    */
    

      

    I. Rage Minimum Query

    若修改是往小修改,那么显然可以$O(1)$直接更新全局最小值。

    否则若目前是将最小值往大了修改,那么这是小概率事件,直接$O(n)$重算全局最小值即可。

    #include<cstdio>
    typedef unsigned int U;
    int n,q;
    U x0,x1,a,b,c,i,x,v[10000010],mi,ans,p=1;
    inline U nxt(){
        U t=x0*a+x1*b+c;
        x0=x1;
        x1=t;
        return x0>>2;
    }
    int main(){
        scanf("%d%d%u%u%u%u%u",&n,&q,&x0,&x1,&a,&b,&c);
        for(i=0;i<n;i++)v[i]=~0U>>1;
        mi=~0U>>1;
        while(q--){
            i=nxt()%n;
            x=nxt();
            if(x<=v[i]){
                if(x<mi)mi=x;
                v[i]=x;
            }else if(v[i]>mi){
                v[i]=x;
            }else{
                v[i]=x;
                mi=x;
                for(i=0;i<n;i++)if(v[i]<mi)mi=v[i];
            }
            p*=10099;
            ans+=p*mi;
        }
        printf("%u",ans);
    }
    

      

    J. Regular Cake

    在正$n$边形与正$m$边形之间紧贴一个正$lcm(n,m)$边形,可以得到答案为:

    [frac{cosleft(frac{pi}{lcm(n,m)} ight) anleft(frac{pi}{m} ight)}{sinleft(frac{pi}{n} ight)}]

    #include<cstdio>
    #include<cmath>
    typedef long long ll;
    using namespace std;
    const double pi=acos(-1.0);
    ll n,m,k;
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    int main(){
        scanf("%lld%lld",&n,&m);
        k=n*m/gcd(n,m);
        printf("%.13f",cos(pi/k)*tan(pi/m)/sin(pi/n));
    }
    

      

    K. Piecemaking

    树形DP,设$f[i][j]$表示考虑$i$的子树,$i$点颜色为$j$的最小代价。

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

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=200010;
    const ll inf=1LL<<60;
    int n,m,i,x,y,z,g[N],v[N<<1],w[N<<1],nxt[N<<1],ed;
    int col[N];
    ll f[N][3],h[3],ans;
    inline void up(ll&a,ll b){a>b?(a=b):0;}
    inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
    void dfs(int x,int y){
        for(int i=0;i<3;i++)f[x][i]=inf;
        f[x][col[x]]=0;
        for(int i=g[x];i;i=nxt[i]){
            int u=v[i];
            if(u==y)continue;
            dfs(u,x);
            for(int j=0;j<3;j++)h[j]=inf;
            for(int j=0;j<3;j++)if(f[x][j]<inf)for(int k=0;k<3;k++)if(f[u][k]<inf){
                //cut
                up(h[j],f[x][j]+f[u][k]+w[i]);
                //merge
                if(j&&k&&j!=k)continue;
                up(h[max(j,k)],f[x][j]+f[u][k]);
            }
            for(int j=0;j<3;j++)f[x][j]=h[j];
        }
    }
    int main(){
        scanf("%d",&n);
        for(i=1;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
        scanf("%d",&m);
        while(m--)scanf("%d",&x),col[x]=1;
        scanf("%d",&m);
        while(m--)scanf("%d",&x),col[x]=2;
        dfs(1,0);
        ans=inf;
        for(i=0;i<3;i++)up(ans,f[1][i]);
        printf("%lld",ans);
    }
    /*
    6
    1 2 5
    2 4 4
    2 5 1
    1 3 2
    3 6 7
    1 4
    2 5 6
    */
    

      

  • 相关阅读:
    CNN comprehension
    Gradient Descent
    Various Optimization Algorithms For Training Neural Network
    gerrit workflow
    jenkins job配置脚本化
    Jenkins pipeline jobs隐式传参
    make words counter for image with the help of paddlehub model
    make words counter for image with the help of paddlehub model
    git push and gerrit code review
    image similarity
  • 原文地址:https://www.cnblogs.com/clrs97/p/7513054.html
Copyright © 2011-2022 走看看