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
    */
    

      

  • 相关阅读:
    AT&T不能访问公司网络
    尝鲜:windows 7 来了
    .net控件编程 资料篇
    Annual part 2009
    从Visual studio 2005移出Visual Assist
    不能在IIS 5.1增加应用程序扩展的BUG
    The problem of the user is not associated with a trusted sql server connection 混合登录选项设置的问题
    让我们难忘的那些歌曲
    分享利用VPC防止病毒软件的进入你的windows电脑
    杂读 May 12,2008
  • 原文地址:https://www.cnblogs.com/clrs97/p/7513054.html
Copyright © 2011-2022 走看看