zoukankan      html  css  js  c++  java
  • XV Open Cup named after E.V. Pankratiev. GP of America

    A. Area of Effect

    首先最优解中必有一个点在圆的边界上。

    若半径就是$R$,则枚举一个点,然后把剩下的事件极角扫描即可,时间复杂度$O(m(n+m)log(n+m))$。

    否则圆必然撞到了两个圆,枚举一个点以及两个圆,二分出最大的半径,然后统计内部点数即可,时间复杂度$O(n^2m(n+m))$。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef pair<ld,int>P;
    const int N=2100;
    const ld eps=1e-9,eps2=1e-4,pi=acos(-1.0);
    int n,m,i,j,k,ans=1;ll R,d[N][N];P q[N*2];
    struct C{ll x,y,r;}a[N];
    struct Circle{
      ld x,y,r;
      Circle(){}
      Circle(ld _x,ld _y,ld _r){x=_x,y=_y,r=_r;}
    };
    inline int sgn(ld x){
      if(x>eps)return 1;
      if(x<-eps)return -1;
      return 0;
    }
    inline int sgn2(ld x){
      if(x>eps2)return 1;
      if(x<-eps2)return -1;
      return 0;
    }
    inline ll sqr(ll x){return x*x;}
    inline ld sqr(ld x){return x*x;}
    inline void fix(ld&x){
      while(sgn(x)<0)x+=pi*2;
      while(sgn(x-pi*2)>=0)x-=pi*2;
      x=max(x,(ld)0.0);
    }
    inline void solve1(int x){
      int i,ret=1,cnt=0;
      for(i=1;i<=n+m;i++)if(i!=x){
        if(d[x][i]>sqr(R*2+a[i].r))continue;
        if(d[x][i]==sqr(R*2+a[i].r)&&i<=n)continue;
        ld A=R,B=R+a[i].r,C=sqrt(d[x][i]);
        if(i<=n)B-=1e-6;
        ld o=acos((A*A+d[x][i]-B*B)/(2.0*A*C));
        ld w=atan2(a[i].y-a[x].y,a[i].x-a[x].x);
        ld l=w-o,r=w+o;
        fix(l),fix(r);
        if(!sgn(l-r))r=l+eps;
        int v=i<=n?-N:1;
        if(l>r)ret+=v;
        q[++cnt]=P(l,v),q[++cnt]=P(r,-v);
      }
      ans=max(ans,ret);
      sort(q+1,q+cnt+1);
      for(i=1;i<=cnt;i++)ans=max(ans,ret+=q[i].second);
    }
    inline void circle_intersection(const Circle&a,const Circle&b,ld&X,ld&Y,int t){
      ld d2=sqr(a.x-b.x)+sqr(a.y-b.y),d=sqrt(d2);
      ld l=(d2+sqr(a.r)-sqr(b.r))/(2.0*d),h=sqrt(max(sqr(a.r)-sqr(l),(ld)0.0));
      ld vlx=(b.x-a.x)/d*l,vly=(b.y-a.y)/d*l;
      ld vhx=-(b.y-a.y)/d*h,vhy=(b.x-a.x)/d*h;
      if(t==1)vhx*=-1,vhy*=-1;
      X=a.x+vlx+vhx;
      Y=a.y+vly+vhy;
    }
    inline void work(ld x,ld y,ld r){
      for(int i=1;i<=n;i++)if(sgn2(sqr(x-a[i].x)+sqr(y-a[i].y)-sqr(r+a[i].r))<0)return;
      int ret=0;
      r=sqr(r);
      for(int i=n+1;i<=n+m;i++)if(sgn2(sqr(x-a[i].x)+sqr(y-a[i].y)-r)<=0)ret++;
      ans=max(ans,ret);
    }
    inline void solve3(int x,int y,int z){
      if(d[x][y]>=sqr(R*2+a[x].r+a[y].r))return;
      for(int _=0;_<2;_++){
        ld l=(sqrt(d[x][z])-a[x].r)/2.0,r=R,X,Y;
        for(int i=0;i<100;i++){
          ld mid=(l+r)/2.0;
          circle_intersection(Circle(a[x].x,a[x].y,a[x].r+mid),Circle(a[z].x,a[z].y,mid),X,Y,_);
          if(sgn2(sqr(X-a[y].x)+sqr(Y-a[y].y)-sqr(a[y].r+mid))>=0)l=mid;else r=mid;
        }
        circle_intersection(Circle(a[x].x,a[x].y,a[x].r+l),Circle(a[z].x,a[z].y,l),X,Y,_);
        work(X,Y,l);
      }
    }
    int main(){
      scanf("%d%d%lld",&n,&m,&R);
      for(i=1;i<=n;i++)scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].r);
      for(i=1;i<=m;i++)scanf("%lld%lld",&a[i+n].x,&a[i+n].y);
      for(i=1;i<=n+m;i++)for(j=1;j<=n+m;j++)d[i][j]=sqr(a[i].x-a[j].x)+sqr(a[i].y-a[j].y);
      for(i=1;i<=m;i++)solve1(i+n);
      for(i=1;i<=n;i++)for(j=1;j<i;j++)for(k=1;k<=m;k++)solve3(i,j,k+n);
      printf("%d",ans);
    }
    

      

    B. Canyon Mapping

    二分答案,求出多边形的包围盒,那么某个正方形的某个顶点必然与包围盒的某个顶点重合,爆搜即可。

    时间复杂度$O(4^3nlog w)$。

    C. Magic Checkerboard

    枚举奇偶性然后贪心构造即可。

    #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 = 2020, M = 0, Z = 1e9 + 7; LL inf = 1e18;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    int n,m;
    int a[N][N];
    int b[N][N];
    void tryit(int y, int x, int oe)
    {
        int val = 2 - oe;
        if(x > 1)gmax(val, b[y][x - 1] + 1);
        if(y > 1)gmax(val, b[y - 1][x] + 1);
        if(val % 2 != oe)++val;
        b[y][x] = val;
    }
    void hahatry(int y, int x)
    {
        int val = 1;
        if(x > 1)gmax(val, b[y][x - 1] + 1);
        if(y > 1)gmax(val, b[y - 1][x] + 1);
        b[y][x] = val;
    }
    LL checkok()
    {
        LL sum = 0;
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= m; ++j)
            {
                if(i > 1 && b[i][j] <= b[i - 1][j])return inf;
                if(j > 1 && b[i][j] <= b[i][j - 1])return inf;
                if(i > 1)
                {
                    if(j > 1)
                    {
                        if((b[i][j] ^ b[i - 1][j - 1]) % 2 == 0)return inf;
                    }
                    if(j < m)
                    {
                        if((b[i][j] ^ b[i - 1][j + 1]) % 2 == 0)return inf;
                    }
                }
                sum += b[i][j];
            }
        }
        return sum;
    }
    LL solve()
    {
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= m; ++j)
            {
                if(i > 1)
                {
                    if(j > 1 && a[i][j] * a[i - 1][j - 1])
                    {
                        if((a[i][j] ^ a[i - 1][j - 1]) % 2 == 0)return -1;
                    }
                    if(j < m && a[i][j] * a[i - 1][j + 1])
                    {
                        if((a[i][j] ^ a[i - 1][j + 1]) % 2 == 0)return -1;
                    }
                }
            }
        }
        LL ans = inf;
        for(int x = 0; x < 2; ++x)
        //int x = 1;
        {
            for(int y = 0; y < 2; ++y)
            //int y = 0;
            {
                memcpy(b, a, sizeof(a));
                for(int i = 1; i <= n; ++i)
                {
                    for(int j = 1; j <= m; ++j)if(b[i][j] == 0)
                    {
                        if((i + j) % 2 == 0)
                        {
                            if((i - 1) % 2 == 0)
                            {
                                if(n == 1 || m == 1)hahatry(i,j);
                                else tryit(i, j, x);
                            }
                            else
                            {
                                if(n == 1 || m == 1)hahatry(i,j);
                                else tryit(i, j, 1 ^ x);
                            }
                        }
                        else
                        {
                            if((i - 1) % 2 == 0)
                            {
                                if(n == 1 || m == 1)hahatry(i,j);
                                else tryit(i, j, y);
                            }
                            else
                            {
                                if(n == 1 || m == 1)hahatry(i,j);
                                else tryit(i, j, 1 ^ y);
                            }
                        }
                    }
                }
                if(0)for(int i = 1; i <= n; ++i)
                {
                    for(int j = 1; j <= m; ++j)printf("%d ", b[i][j]);
                    puts("");
                }
                gmin(ans, checkok());
            }
        }
        if(ans == inf)ans = -1;
        return ans;
    }
    int main()
    {
    	while(~scanf("%d%d",&n,&m))
    	{
            for(int i = 1; i <= n; ++i)
            {
                for(int j = 1; j <= m; ++j)
                {
                    scanf("%d", &a[i][j]);
                }
            }
            printf("%lld
    ", solve());
    	}
    	return 0;
    }
    
    /*
    【trick&&吐槽】
    4 4
    1 2 3 0
    0 0 5 6
    0 0 7 8
    7 0 0 10
    
    4 4
    1 2 3 0
    0 0 5 6
    0 4 7 8
    7 0 0 10
    
    2 3
    0 0 0
    0 0 0
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    D. Extensive OR

    从高到低考虑每一位,一旦有个数字脱离了限制,也就是说这个数字这一位是$1$,但是强制填了$0$。那么除了这一位之外,其它位可以乱填,它自己方案唯一。
    枚举脱离的那一位,设$f[i][j][l]$表示前$i$个数字,当前位$xor$为$j$,是否有数字脱离限制的方案数。如此求出$g[i]$表示$i$个数(允许重复)的答案。

    考虑容斥,枚举$n$的所有等价类方案,贡献为:

    $(-1)^{n-等价类个数} imes(每个等价类大小-1)!之积 imes 方案数$

    $方案数=g[奇数大小的等价类个数] imes g[2]^{偶数大小的等价类个数}$。

    最后答案再除以$n!$即可。

    时间复杂度$O(nk|S|+Bell(n))$。

    #include<cstdio>
    #include<cstring>
    const int N=10,P=1000000007,inv=(P+1)/2;
    int n,m,K,i,j,k,x,y,o,f[N][2][2],g[N],w[N],ans;
    char a[5000050],flag[N];
    int pow(int a,int b){
    	int t=1;
    	for(;b;b>>=1,a=1LL*a*a%P)if(b&1)t=1LL*t*a%P;
    	return t;
    }
    inline void up(int&a,int b){a=a+b<P?a+b:a+b-P;}
    void dfs(int x,int y){
    	if(x==n){
    		int i,j,k=(n-y)&1?-1:1,t=0;
    		for(i=1;i<=y;i++){
    			for(j=2;j<w[i];j++)k*=j;
    			if(w[i]&1)t++;
    		}
    		if(k<0)k+=P;
    		ans=(1LL*k*g[t]%P*pow(g[2],y-t)+ans)%P;
    		return;
    	}
    	for(int i=1;i<=y+1;i++){
    		w[i]++;
    		dfs(x+1,i>y?i:y);
    		w[i]--;
    	}
    }
    int main(){
    	scanf("%d%d%s",&n,&K,a);
    	m=strlen(a);
    	for(i=0;i<m;i++)for(j=1,k=i+m;j<K;j++,k+=m)a[k]=a[i];
    	m*=K;
    	for(i=0;i<m;i++)a[i]-='0';
    	for(i=m-1;~i;i--){
    		a[i]^=1;
    		if(!a[i])break;
    	}
    	f[0][0][0]=1;
    	y=pow(2,m);
    	for(i=0;i<m;i++)x=(x*2+a[i])%P;
    	up(x,1);
    	for(i=m-1;~i;i--){
    		y=1LL*y*inv%P;
    		o=a[m-i-1];
    		if(o)up(x,P-y);
    		if(o){
    			for(j=1;j<=n;j++){
    				f[j][0][0]=f[j][0][1]=f[j][1][0]=f[j][1][1]=0;
    				for(k=0;k<2;k++){
    					if(f[j-1][k][0]){
    						f[j][k^1][0]=(1LL*f[j-1][k][0]*x+f[j][k^1][0])%P;
    						up(f[j][k][1],f[j-1][k][0]);
    					}
    					if(f[j-1][k][1]){
    						f[j][k][1]=(1LL*f[j-1][k][1]*y+f[j][k][1])%P;
    						f[j][k^1][1]=(1LL*f[j-1][k][1]*x+f[j][k^1][1])%P;
    					}
    				}
    			}
    		}else{
    			for(j=1;j<=n;j++){
    				f[j][0][0]=f[j][0][1]=f[j][1][0]=f[j][1][1]=0;
    				for(k=0;k<2;k++){
    					if(f[j-1][k][0]){
    						f[j][k][0]=(1LL*f[j-1][k][0]*x+f[j][k][0])%P;
    					}
    					if(f[j-1][k][1]){
    						f[j][k][1]=(1LL*f[j-1][k][1]*x+f[j][k][1])%P;
    					}
    				}
    			}
    		}
    		for(j=1;j<=n;j++)if(!flag[j]){
    			up(g[j],f[j][0][1]);
    			if(o&(j&1))flag[j]=1;
    		}
    	}
    	for(i=1;i<=n;i++)if(!flag[i])up(g[i],1);
    	g[0]=g[1]=1;
    	dfs(0,0);
    	for(i=2;i<=n;i++)ans=1LL*ans*pow(i,P-2)%P;
    	printf("%d",ans);
    }
    

      

    E. Primal Partitions

    设$f[i][j]$表示把$[1,j]$分成$i$段的最大得分,注意到区间$gcd$只有本质不同的$O(nlog v)$段,用ST表优化转移即可。

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

    #include<cstdio>
    const int N=20010,M=1000010;
    int n,m,i,j,tot,p[M],vis[M],w[M],l[N],v[N];
    int a[N],Log[N],dp[N],f[15][N];
    struct E{
    	int x,y,r,w;
    	E(){}
    	E(int _x,int _y,int _r,int _w){x=_x,y=_y,r=_r,w=_w;}
    }e[M];
    inline int max(int a,int b){return a>b?a:b;}
    inline int min(int a,int b){return a<b?a:b;}
    inline void up(int&a,int b){a<b?(a=b):0;}
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    inline int ask(int l,int r){
    	int k=Log[r-l+1];
    	return max(f[k][l],f[k][r-(1<<k)+1]);
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(i=2;i<=1000000;i++){
    		if(!vis[i])vis[i]=i,p[tot++]=i;
    		for(j=0;j<tot&&i*p[j]<=1000000;j++){
    			vis[i*p[j]]=p[j];
    			if(i%p[j]==0)break;
    		}
    	}
    	for(i=2;i<=1000000;i++){
    		j=i;
    		while(j>1){
    			w[i]=max(w[i],vis[j]);
    			j/=vis[j];
    		}
    	}
    	for(i=1;i<=n;i++)scanf("%d",&a[i]);
    	tot=0;
    	for(i=1;i<=n;i++)for(v[i]=a[i],j=l[i]=i;j;j=l[j]-1){
    		v[j]=gcd(v[j],a[i]);
    		while(l[j]>1&&gcd(a[i],v[l[j]-1])==gcd(a[i],v[j]))l[j]=l[l[j]-1];
    		e[++tot]=E(l[j],j,i,w[v[j]]);
    	}
    	dp[1]=a[1];
    	for(i=2;i<=n;i++)dp[i]=gcd(dp[i-1],a[i]);
    	for(i=1;i<=n;i++)dp[i]=w[dp[i]];
    	for(i=2;i<=n+1;i++)Log[i]=Log[i>>1]+1;
    	while(m>1){
    		m--;
    		for(i=0;i<=n;i++)f[0][i]=dp[i],dp[i]=0;
    		for(j=1;j<15;j++)for(i=0;i+(1<<j)-1<=n;i++)f[j][i]=max(f[j-1][i],f[j-1][i+(1<<(j-1))]);
    		for(i=1;i<=tot;i++)up(dp[e[i].r],min(ask(e[i].x-1,e[i].y-1),e[i].w));
    	}
    	printf("%d",dp[n]);
    }
    

      

    F. Sand Art

    二分差值,显然最高的是不变的,对于剩下的用网络流判定是否有解即可。

    #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 = 420, M = 1e6 + 10, Z = 1e9 + 7;
    template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
    int casenum, casei;
    const double inf = 1e9;
    
    int ST, ED;
    int first[N], id;
    int w[M], nxt[M];
    double cap[M];
    
    void ins(int x, int y, double cap_)
    {
        w[++ id] = y;
        cap[id] = cap_;
        nxt[id] = first[x];
        first[x] = id;
        w[++ id] = x;
        cap[id] = 0;
        nxt[id] = first[y];
        first[y] = id;
    }
    int d[N];
    const double eps = 1e-6;
    int sgn(double x)
    {
        if(fabs(x) < eps) return 0;
        return x > 0 ? 1 : -1;
    }
    
    bool bfs()
    {
        MS(d, -1);
        queue<int> q; q.push(ST); d[ST] = 0;
        while(! q.empty()){
            int x = q.front(); q.pop();
            for(int z = first[x]; z; z = nxt[z]) if(sgn(cap[z])){
                int y = w[z];
                if(d[y] == -1){
                    d[y] = d[x] + 1;
                    q.push(y);
                    if(y == ED) return 1;
                }
            }
        }
        return 0;
    }
    
    double dfs(int x, double all)
    {
        if(x == ED) return all;
        double use = 0;
        for(int z = first[x]; z; z = nxt[z]) if(sgn(cap[z])){
            int y = w[z];
            if(d[y] == d[x] + 1){
                double tmp = dfs(y, min(cap[z], all - use));
                cap[z] -= tmp;
                cap[z ^ 1] += tmp;
                use += tmp;
                if(sgn(use - all) == 0) break;
            }
        }
        if(sgn(use) == 0) d[x] = -1;
        return use;
    }
    
    
    double dinic()
    {
        double ret = 0;
        while(bfs()) ret += dfs(ST, inf);
        return ret;
    }
    int n, m;
    double v[N], h[N], W, H, x[N];
    double minv[N][N], maxv[N][N];
    double minh, maxh;
    
    bool build(double mid)
    {
        double top = maxh - mid;
        MS(first, 0); id = 1;
        double allv = 0;
        for(int i = 1; i <= n; i ++){
            if(sgn(top - h[i]) > 0) allv += (top - h[i]) * x[i];
        }
        for(int j = 1; j <= m; j ++){
            for(int i = 1; i <= n; i ++){
                if(sgn(top - h[i]) > 0) {
                    double cap_ = min((top - h[i]) * x[i], maxv[i][j] - minv[i][j]);
                    ins(j, i + m, cap_);
                }
            }
        }
        ST = 0, ED = n + m + 1;
        for(int i = 1; i <= n; i ++){
            if(sgn(top - h[i]) > 0) ins(i + m, ED, (top - h[i]) * x[i]);
        }
        for(int i = 1; i <= m; i ++){
            ins(ST, i, v[i]);
        }
        if(sgn(dinic() - allv) != 0) return 1;
        return 0;
    }
    
    int main()
    {
    	scanf("%d%d%lf%lf", &n, &m, &W, &H);
    	for(int i = 1; i <= m; i ++){
            scanf("%lf", &v[i]);
    	}
    	for(int i = 1; i < n; i ++){
            scanf("%lf", &x[i]);
    	}
    	x[n] = W;
    	for(int i = n; i >= 1; i --){
            x[i] = x[i] - x[i - 1];
            //x[i] *= H;
    	}  // 每个容器的宽度
    
    	for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= m; j ++){
                scanf("%lf", &minv[i][j]);
            }
    	}
    	for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= m; j ++){
                scanf("%lf", &maxv[i][j]);
            }
    	}
    	maxh = 0, minh = 1e9;
    	for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= m; j ++){
                h[i] += minv[i][j] / x[i];
                v[j] -= minv[i][j];
            }
            gmax(maxh, h[i]);
            gmin(minh, h[i]);
    	}
    	double r = maxh - minh, l = 0;
    	for(int tim = 1; tim <= 200; tim ++){
            double mid = (l + r) / 2;
            if(build(mid)) l = mid;
            else r = mid;
    	}
    	printf("%.6f
    ", l);
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    2 2 5 5
    2.0 2.0
    4.0
    1.0 0.0
    0.0 1.0
    1.0 0.0
    1.0 2.0
    
    2 2 5 5
    2.0 2.0
    4.0
    1.0 0.0
    0.0 1.0
    1.5 0.0
    0.0 2.0
    
    2 5 11 10
    3.0 4.0 4.0 9.0 2.0
    4.0
    2.0 2.0 1.0 0.5 0.25
    0.0 2.0 0.0 4.0 1.0
    2.0 2.0 3.0 4.0 0.75
    0.0 2.1 0.0 5.1 1.1
    
    
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    G. String Stretching

    枚举长度$len$,那么$len$必须要是$n$的约数,然后枚举每个长度为$len$的子串$S$,检查是否可行。

    对于检查,设$f[i][j]$表示区间$[i,j]$能否通过$S$产生,要么在末尾产生某个长度为$len$倍数的区间,要么接着匹配一位,时间复杂度$O(frac{n^3}{len})$。

    总时间复杂度$O(n^3d(n)log n)$。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=210;
    char a[N],b[N],c[N],fin[N];
    int n,i;
    int cnt;
    bool f[N][N];
    string best;
    inline bool check(int len,string cur){
    	int i,j,k;
    	//cout<<len<<" "<<cur<<endl;
    	for(i=1;i<=len;i++)b[i]=cur[i-1];
    	int tot=0;
    	for(i=1;i*len<=n;i++)for(j=1;j<=len;j++)c[++tot]=b[j];
    	sort(c+1,c+n+1);
    	for(i=1;i<=n;i++)if(c[i]!=fin[i])return 0;
    	for(i=0;i<=n+1;i++)for(j=0;j<=n+1;j++)f[i][j]=0;
    	for(i=n;i;i--){
    		f[i][i-1]=1;
    		for(j=i;j<=n;j++){
    			for(k=j-len;k>=i-1;k-=len){
    				if(f[i][k]&&f[k+1][j]){f[i][j]=1;break;}
    			}
    			int o=j-i+1;
    			o%=len;
    			if(!o)o+=len;
    			if(f[i][j-1]&&a[j]==b[o])f[i][j]=1;
    		}
    	}
    	return f[1][n];
    }
    void solve(int len){
    	if(n%len)return;
    	for(int i=1;i+len-1<=n;i++){
    		string now="";
    		for(int j=0;j<len;j++)now.push_back(a[i+j]);
    		if(cnt&&best<=now)continue;
    		if(check(len,now)){
    			cnt++;
    			best=now;
    		}
    	}
    	if(cnt){
    		cout<<best<<endl;
    		exit(0);
    	}
    }
    int main(){
    	scanf("%s",a+1);
    	n=strlen(a+1);
    	for(i=1;i<=n;i++)fin[i]=a[i];
    	sort(fin+1,fin+n+1);
    	for(i=1;i<n;i++)solve(i);
    	puts(a+1);
    }
    /*
    hhehellolloelhellolo
    */
    

      

    H. Vending Machine

    将差值看成边权,并添加$0$边来消除负数,首先可以贪心将每个点都买到剩一个。

    那么若是树或者自环,则答案为每个点的入边中权值的最大值。

    对于环来说,必须要删掉环上一条边,枚举每条边删除即可。

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

    #include<cstdio>
    #include<set>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>P;//w[son],son
    const int N=100010;
    int n,i,j,k,f[N],p[N],m[N],s[N],w[N];
    ll ans;
    int t,q[N];
    int fa[N],vf[N],vis[N];
    set<P>T[N];
    int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
    inline void merge(int x,int y){
    	if(F(x)!=F(y))fa[fa[x]]=fa[y];
    }
    inline ll cal(int x){
    	int y=f[x];
    	ll pre=T[y].rbegin()->first;
    	T[y].erase(P(w[x],x));
    	ll now=T[y].rbegin()->first;
    	T[y].insert(P(w[x],x));
    	return now-pre;
    }
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)scanf("%d%d%d%d",&f[i],&p[i],&m[i],&s[i]);
    	for(i=1;i<=n;i++)T[i].insert(P(0,0));
    	for(i=1;i<=n;i++){
    		w[i]=m[f[i]]-p[i];
    		T[f[i]].insert(P(w[i],i));
    	}
    	for(i=1;i<=n;i++)ans+=1LL*(T[i].rbegin()->first)*s[i];
    	for(i=1;i<=n;i++)fa[i]=i;
    	for(i=1;i<=n;i++)merge(i,f[i]);
    	for(i=1;i<=n;i++)if(!vf[F(i)]){
    		vf[fa[i]]=1;
    		for(j=i;!vis[j];j=f[j])vis[j]=1;
    		q[t=1]=j;
    		for(k=f[j];k!=j;k=f[k])q[++t]=k;
    		if(t==1)continue;
    		ll tmp=-(1LL<<60);
    		for(j=1;j<=t;j++){
    			tmp=max(tmp,cal(q[j]));
    		}
    		ans+=tmp;
    	}
    	printf("%lld",ans);
    }
    /*
    5
    5 9 2 2
    1 1 7 4
    2 3 6 3
    2 2 9 6
    1 4 5 1
    */
    

      

    I. Rainbow Zamboni

    首先通过公式直接求出终点,然后倒着模拟,最多模拟$O(R+C)$轮后每个点都会被经过至少一次,无需接着模拟。

    时间复杂度$O((R+C)^2)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    ll x, y;
    ll n;
    int R,C;
    int ret;
    const int N=2222;
    char f[N][N],vis[N][N];
    
    void solve(int d, ll i)
    {
    	if(d==0){
    		x+=i;
    	}
    	if(d==1){
    		y-=i;
    	}
    	if(d==2){			
    		x-=i;
    	}
    	if(d==3){
    		y+=i;
    	}
    		
    	if(d==0){
    		y++;
    	}
    	if(d==1){
    		x++;
    	}
    	if(d==2){
    		y--;
    	}
    	if(d==3){
    		x--;
    	}
    		
    }
    
    ll mo(ll a,ll b){return (a%b+b)%b;}
    
    inline void col(int x,int y,int c){
    	if(!vis[x][y]){
    		vis[x][y]=1;
    		f[x][y]=c;
    		ret--;
    	}
    }
    inline void moveup(int x,int l,int r,int c){
    	for(int i=l;i<=r;i++)col(x,i,c);
    }
    inline void moveright(int y,int l,int r,int c){
    	for(int i=l;i<=r;i++)col(i,y,c);
    }
    
    inline void walk(ll x1,ll y1,ll x2,ll y2,int c){
    	if(x1==x2){
    		if(y1>y2)swap(y1,y2);
    		ll k=y2-y1+1;
    		y1=mo(y1,C);
    		if(k>=C)moveup(mo(x1,R),0,C-1,c);
    		else{
    			if(y1+k-1<C)moveup(mo(x1,R),y1,y1+k-1,c);
    			else{
    				moveup(mo(x1,R),y1,C-1,c);
    				moveup(mo(x1,R),0,mo(y2,C),c);
    			}
    		}
    	}else{
    		if(x1>x2)swap(x1,x2);
    		ll k=x2-x1+1;
    		x1=mo(x1,R);
    		if(k>=R)moveright(mo(y1,C),0,R-1,c);
    		else{
    			if(x1+k-1<R)moveright(mo(y1,C),x1,x1+k-1,c);
    			else{
    				moveright(mo(y1,C),x1,R-1,c);
    				moveright(mo(y1,C),0,mo(x2,R),c);
    			}
    		}
    	}
    }
    
    void solve2(ll n, int d,int c)
    {
    	ll xx = x, yy = y;
    	if(d == 0){		// rgt
    		x += n;
    	}
    	else if(d == 1){	// down
    		y -= n;
    	}
    	else if(d == 2){	// lft
    		x -= n;
    	}	
    	else if(d == 3){	// up
    		y += n;
    	}
    	walk(xx,yy,x,y,c);
    	if(d == 0){		// rgt
    		y ++;
    	}
    	else if(d == 1){	// down
    		x ++;
    	}
    	else if(d == 2){	// lft
    		y --;
    	}	
    	else if(d == 3){	// up
    		x --;
    	}
    }
    int main()
    {
    	scanf("%d%d",&R,&C);
    	scanf("%lld%lld",&x,&y);
    	
    	
    	x=R-x+1;
    	swap(x,y);
    	swap(R,C);
    	
    	scanf("%lld", &n);
    	
    	x--,y--;
    	x%=R;
    	y%=C;
    	
    	
    	ll A = n / 4, B = n % 4;
    	x += -2 * A + 1, y += -2 * A;
    	x%=R;
    	y%=C;
    	for(int i = 0; i < B; i ++){
    		solve((i+3)%4, A * 4 + i);
    		x%=R;
    		y%=C;
    	}
    	for(int i=0;i<R;i++)for(int j=0;j<C;j++){
    		f[i][j]='.';
    		ret++;
    	}
    	if(n%4==0){
    		col(mo(x-1,R),mo(y,C),'@');
    	}
    	if(n%4==1){
    		col(mo(x,R),mo(y+1,C),'@');
    	}
    	if(n%4==2){
    		col(mo(x+1,R),mo(y,C),'@');
    	}
    	if(n%4==3){
    		col(mo(x,R),mo(y-1,C),'@');
    	}
    	for(ll i=n;i;i--){
    		solve2(i-1, i % 4,(i-1+26)%26+'A');
    		x%=R;
    		y%=C;
    		if(!ret)break;
    	}
    	for(int j=C-1;~j;j--){
    		for(int i=0;i<R;i++)putchar(f[i][j]);
    		puts("");
    	}
    }
    

      

    J. Zig Zag Nametag

    贪心构造即可。

    #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 = 1e6 + 30, 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, K;
    int f[N][26];
    void print(int len, int first)
    {
        printf("%c", 'a' + first);
        for(int nxt = 0; nxt < 26; ++nxt)
        {
            int add = abs(first - nxt);
            if(len >= add && f[len - add][nxt] + 1 == f[len][first])
            {
                print(len - add, nxt);
                break;
            }
        }
    }
    char s[N];
    int main()
    {
    	while(~scanf("%d",&K))
        {
            int n = K / 25 + (K % 25 > 0) + 1;
            for(int i = 1; i <= n; ++i)
            {
                s[i] = i % 2 == 1 ? 'a' : 'z';
            }
            s[n + 1] = 0;
            int dif = (n - 1) * 25 - K;
            if(n == 2)
            {
                s[2] -= dif;
            }
            else
            {
                int diff = dif / 2;
                s[2] -= diff;
                if(s[n] == 'a')s[n] += dif % 2;
                else s[n] -= dif % 2;
            }
            puts(s + 1);
        }
    	return 0;
    	for(K = 1; K <= 200; ++K)
    	{
            MS(f, 63);
    	    for(int j = 0; j < 26; ++j)
            {
                f[0][j] = 1;
            }
            for(int i = 0; i <= K; ++i)
            {
                for(int j = 0; j < 26; ++j)if(f[i][j] != inf)
                {
                    for(int k = 0; k < 26; ++k)
                    {
                        int add = abs(j - k);
                        gmin(f[i + add][k], f[i][j] + 1);
                    }
                }
            }
            int len = -1, pos = 0;
            for(int i = 0; i < 26; ++i)
            {
                if(f[K][i] < len)
                {
                    len = f[K][i];
                    pos = i;
                }
            }
            print(K, pos);
            puts("");
    	}
    	return 0;
    }
    
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

  • 相关阅读:
    CruiseControl.NET 三言两语
    在MFC程序中增加控制台
    VS2005 编译Release版本出现清单文件的错误
    内存泄露问题
    软件设计原则
    boost::shared_ptr 分析与实现
    corelDraw 的CDR格式解析
    13. 量词操作符—【LINQ标准查询操作符】
    SQL SERVER执行查询的顺序
    CSLA命令对象的简单封装
  • 原文地址:https://www.cnblogs.com/clrs97/p/8025819.html
Copyright © 2011-2022 走看看