zoukankan      html  css  js  c++  java
  • 2017-2018 ACM-ICPC Southeast Regional Contest (Div. 1)

    A. Ducks in a Row

    当$n imes k>|S|$时,显然无解。

    否则最优解中翻转的区间一定两两不相交,设$f[i][j][x][y]$表示考虑前$i$个位置,第$i$个位置翻转情况为$j$,当前连续段长度为$x$,已有$y$个长度至少为$n$的$D$连续段的最少翻转次数,然后转移即可。

    时间复杂度$O(|S|^2)$。

    #include<cstdio>
    #include<cstring>
    const int N=2010,inf=10000000;
    int n,K,m,o,i,j,k,x,y,f[2][2][N][N],ans=inf;
    char a[N];
    inline void up(int&a,int b){a>b?(a=b):0;}
    int main(){
      scanf("%d%d%s",&n,&K,a+1);
      m=strlen(a+1);
      if(n*K>m)return puts("-1"),0;
      //D=1
      //G=0
      for(i=1;i<=m;i++)a[i]=a[i]=='D';
      for(j=0;j<2;j++)for(x=0;x<=n;x++)for(y=0;y<=K;y++)f[0][j][x][y]=inf;
      f[0][0][0][0]=0;
      for(i=0;i<m;i++,o^=1){
        for(j=0;j<2;j++)for(x=0;x<=n;x++)for(y=0;y<=K;y++)f[o^1][j][x][y]=inf;
        for(j=0;j<2;j++)for(x=0;x<=n;x++)for(y=0;y<=K;y++)if(f[o][j][x][y]<inf){
          int w=f[o][j][x][y];
          int pre=a[i]^j;
          for(k=0;k<2;k++){
            int now=a[i+1]^k;
            int len=x,cnt=y;
            if(pre==now){
              if(now)len++;
            }else{
              if(pre&&x>=n)cnt++;
              len=now;
            }
            if(len>n)len=n;
            if(cnt>K)cnt=K;
            up(f[o^1][k][len][cnt],w+(!j&&k));
          }
        }
      }
      for(j=0;j<2;j++)for(x=0;x<=n;x++)for(y=0;y<=K;y++){
        if(y+(x==n)>=K)
          up(ans,f[o][j][x][y]);
      }
      if(ans==inf)ans=-1;
      printf("%d",ans);
    }
    //f[i][fliped?][len][cnt]
    

      

    B. Exciting Finish!

    设$f[S][i][j]$表示已经给$S$集合的人加了分,当前最高分的人是$i$,一共加了$j$分的方案数。

    那么枚举下一个加分的人$k$,则$k$加的分为$q=max(p_i+1-p_k,0)$,因为要求$q$不下降,因此后面所有人都至少加了$q$,把它全部算掉之后,剩下的人(包括$k$)的分差可以等效为初始的$p$的差值,故不需要记录最高分具体是多少以及$q$具体是多少。

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

    #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 = 12, 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, X;
    int a[N];
    int f[1 << N][N][707];
    int dfs(int msk, int pre, int X, int rstnum)
    {
    	if (!rstnum)return 1;
    	if (~f[msk][pre][X])return f[msk][pre][X];
    	int &rtn = f[msk][pre][X];
    	rtn = 0;
    	for (int i = 0; i < n; ++i)if(msk >> i & 1)if(i != pre)
    	{
    		int add = max(a[pre] + 1 - a[i], 0);
    		if (X >= rstnum * add)
    		{
    			rtn += dfs(msk ^ 1 << i, i, X - rstnum * add, rstnum - 1);
    		}
    	}
    	return rtn;
    }
    int main()
    {
    	while (~scanf("%d%d", &n, &X))
    	{
    		for (int i = 0; i < n; ++i)
    		{
    			scanf("%d", &a[i]);
    		}
    		sort(a, a + n);
    		MS(f, -1);
    		printf("%d
    ", dfs((1 << n) - 1, n - 1, X, n));
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    【数据】
    
    
    */
    

      

    C. Flipping Out

    首先建出AC自动机,将$n-1$个已知串的贡献全部删除。

    再对母串差分,可以将信息表示成“丢失串是否是母串的某个前缀的后缀”。

    将串和差分数组翻转,信息则变为“丢失串是否是母串的某个后缀的前缀”。

    若全部都是“否”,则方案数显然为无穷。

    否则随便找到一个“是”的后缀$x$,对于其它每个后缀,求出LCP,那么可以更新$x$可取前缀的取值范围的上下界。

    最后枚举每个可能的丢失串,利用Hash判断是否在$n-1$个串中出现过即可。

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

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<set>
    using namespace std;
    typedef unsigned long long ll;
    const int N=1000010,M=233;
    int n,len,i,x;
    int s[N];
    char a[N];
    int tot,son[N][2],v[N],fail[N];
    set<ll>T;
    int ans,L,R;
    ll p[N],f[N];
    inline void ins(){
      static char s[N];
      scanf("%s",s);
      int l=strlen(s),i;
      for(i=0;i<l;i++)s[i]=s[i]=='H';
      for(int x=i=0,w;i<l;i++){
        w=s[i];
        if(!son[x][w])son[x][w]=++tot;
        x=son[x][w];
        if(i==l-1)v[x]^=1;
      }
      ll t=0;
      for(i=l-1;~i;i--)t=t*M+s[i]+1;
      T.insert(t);
    }
    void make(){
      int h=1,t=0,i,j,x;
      static int q[N];
      fail[0]=-1;
      for(i=0;i<2;i++)if(son[0][i])q[++t]=son[0][i];
      while(h<=t){
        for(x=q[h++],i=0;i<2;i++)
          if(son[x][i]){
            fail[son[x][i]]=son[fail[x]][i];
            v[son[x][i]]^=v[fail[son[x][i]]];
            q[++t]=son[x][i];
          }else son[x][i]=son[fail[x]][i];
      }
    }
    inline ll ask(int l,int r){return f[r]-f[l-1]*p[r-l+1];}
    inline int lcp(int x,int y){
      int l=1,r=min(len-x+1,len-y+1),mid,t=0;
      while(l<=r){
        mid=(l+r)>>1;
        if(ask(x,x+mid-1)==ask(y,y+mid-1))l=(t=mid)+1;else r=mid-1;
      }
      return t;
    }
    int main(){
      scanf("%d",&n);
      for(i=1;i<n;i++)ins();
      make();
      scanf("%s",a+1);
      if(a[1]=='H')return puts("0"),0;
      //T 0 H 1
      len=strlen(a+1);
      for(i=1;i<=len;i++)a[i]=a[i]=='H';
      len--;
      for(i=1;i<=len;i++)s[i]=a[i]^a[i+1];
      for(i=1,x=0;i<=len;i++){
        x=son[x][a[i]];
        s[i]^=v[x];
      }
      reverse(a+1,a+len+1);
      reverse(s+1,s+len+1);
      for(i=1;i<=len;i++)if(s[i])break;
      if(i>len)return puts("-1"),0;
      x=i;
      L=1,R=len-x+1;
      for(p[0]=i=1;i<=len;i++)f[i]=f[i-1]*M+a[i]+1,p[i]=p[i-1]*M;
      //for(i=1;i<=len;i++)printf("%c",a[i]?'H':'T');puts("");
      //for(i=1;i<=len;i++)printf("%d",s[i]);puts("");
      //printf("x=%d
    ",x);
      for(i=1;i<=len;i++){
        int t=lcp(i,x);
        //printf("%d %d
    ",i,t);
        if(s[i]){
          R=min(R,t);
        }else{
          L=max(L,t+1);
        }
      }
      //printf("%d %d
    ",L,R);
      for(i=L;i<=R;i++)if(T.find(ask(x,x+i-1))==T.end())ans++;
      printf("%d",ans);
    }
    /*
    THTTHTT
    0000100
    
    i肯定是1
    一定是[1,i]的某个后缀
    
    枚举0
    那么它和i的最长公共后缀之后的都不行
    
    枚举1
    那么只能是它最长公共后缀
    */
    

      

    D. Jumping Haybales

    BFS求出左上角到每个点的最短路,对于每行每列分别开一个并查集来跳过所有已经访问过的点。

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

    #include<cstdio>
    const int N=2010;
    int n,k,i,d[N][N],h=1,t,q[N*N][2];
    char a[N][N];
    struct DSU{
      int f[N];
      void init(){
        for(int i=1;i<=n+1;i++)f[i]=i;
      }
      int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
    }down[N],right[N];
    inline void ext(int x,int y,int w){
      if(a[x][y]=='#')return;
      if(d[x][y])return;
      d[x][y]=w;
      q[++t][0]=x;
      q[t][1]=y;
    }
    int main(){
      scanf("%d%d",&n,&k);
      for(i=1;i<=n;i++)scanf("%s",a[i]+1);
      for(i=1;i<=n;i++)down[i].init(),right[i].init();
      ext(1,1,1);
      while(h<=t){
        int x=q[h][0];
        int y=q[h++][1];
        int w=d[x][y]+1;
        //right
        for(i=right[x].F(y);i<=y+k&&i<=n;i=right[x].F(i)){
          ext(x,i,w);
          right[x].f[i]++;
        }
        //down
        for(i=down[y].F(x);i<=x+k&&i<=n;i=down[y].F(i)){
          ext(i,y,w);
          down[y].f[i]++;
        }
      }
      printf("%d",d[n][n]-1);
    }
    

      

    F. Move Away

    首先考虑求出一个可行解:它必然是两个圆的交点或者圆上任意一点。

    求出可行解之后,在这个基础上二分答案$mid$,若以原点为圆心,半径为$mid$的圆(内部不算)与其它所有圆(内部要算)的交集非空,则可行。

    同理,交集的可行解只可能是半径为$mid$的圆上任意一点或者它和某个圆的交点,暴力检查即可。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const double eps=1e-9,inf=1e20;
    inline int sig(double x){
      if(x<-eps)return -1;
      if(x>eps)return 1;
      return 0;
    }
    struct P{
      double x,y;
      P(){x=y=0;}
      P(double _x,double _y){x=_x,y=_y;}
      P operator+(P v){return P(x+v.x,y+v.y);}
      P operator-(P v){return P(x-v.x,y-v.y);}
      P operator*(double v){return P(x*v,y*v);}
      P operator/(double v){return P(x/v,y/v);}
      double operator*(P v){return x*v.x+y*v.y;}
      double len(){return hypot(x,y);}
      double len_sqr(){return x*x+y*y;}
      P trunc(double l){return (*this)*l/len();}
      P rot90(){return P(-y,x);}
    };
    struct C{
      P c;double r;
      C(){c=P(0,0),r=0;}
      C(P _c,double _r){c=_c,r=_r;}
    }a[2010];
    inline bool circle_circle_intersection(C a,C b,P&p,P&q){
      double d=(a.c-b.c).len();
      if(d>a.r+b.r)return 0;
      if(d<fabs(a.r-b.r))return 0;
      double l=((a.c-b.c).len_sqr()+a.r*a.r-b.r*b.r)/(2*d),h=sqrt(a.r*a.r-l*l);
      P vl=(b.c-a.c).trunc(l),vh=vl.rot90().trunc(h);
      p=a.c+vl+vh;
      q=a.c+vl-vh;
      return 1;
    }
    int n,i,j,flag,ia,ib;
    double l,r,mid;
    double L,R,MID,t0,t1,D,U,A,B,x,y;
    inline bool ok(P b){
      for(int i=0;i<n;i++)if(sig((b-a[i].c).len()-a[i].r)>0)return 0;
      return 1;
    }
    inline void gao(P b){
      if(!ok(b))return;
      l=max(l,b.len());
    }
    inline bool check(double R){
      a[n].r=R;
      if(ok(P(R,0)))return 1;
      for(int i=0;i<n;i++){
        P a,b;
        if(circle_circle_intersection(::a[i],::a[n],a,b)){
          if(ok(a))return 1;
          if(ok(b))return 1;
        }
      }
      return 0;
    }
    int main(){
      for(scanf("%d",&n);i<n;i++)scanf("%lf%lf%lf",&a[i].c.x,&a[i].c.y,&a[i].r);
      for(i=0;i<n;i++)gao(P(a[i].c.x-a[i].r,a[i].c.y));
      for(i=0;i<n;i++)for(j=0;j<i;j++){
        P a,b;
        if(circle_circle_intersection(::a[i],::a[j],a,b)){
          gao(a);
          gao(b);
        }
      }
      r=1e4;
      for(int _=100;_;_--){
        if(check(mid=(l+r)/2))l=mid;else r=mid;
      }
      printf("%.3f",l);
    }
    

      

    I. Star Arrangements

    按题意模拟即可。

    #define ms(x, y) memset(x, y, sizeof(x))
    #define mc(x, y) memcpy(x, y, sizeof(x))
    #define lson o << 1, l, mid
    #define rson o << 1 | 1, mid + 1, r
    #define ls o << 1
    #define rs o << 1 | 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 = 1e5 + 10, M = 2e6 + 10, Z = 1e9 + 7, maxint = 2147483647, ms1 = 16843009, ms31 = 522133279, ms63 = 1061109567, ms127 = 2139062143;
    const double PI = acos(-1.0), eps = 1e-8;
    typedef long long LL;
    void fre()
    {
        freopen("/Users/luras/Desktop/in.txt", "r", stdin);
        freopen("/Users/luras/Desktop/out.txt", "w", stdout);
    }
    const int INF = 1e9;
    int casenum, casei;
    int n;
    
    bool c1(int i)
    {
    	if(n % (2 * i - 1)) return 0;
    	int x = n / (2 * i - 1);
    	if(x > 0) return 1;
    	return 0;
    }
    bool c2(int i)
    {
    	if((n - 1 + i) % (2 * i - 1)) return 0;
    	int x = (n - 1 + i) / (2 * i - 1);
    	if(x > 1) return 1;
    	return 0;
    }
    bool c3(int i)
    {
    	if(n % (2 * i)) return 0;
    	int x = n / (2 * i);
    	if(x > 0) return 1;
    	return 0;
    }
    bool c4(int i)
    {
    	if((n + i) % (2 * i)) return 0;
    	int x = (n + i) / (2 * i);
    	if(x > 1) return 1;
    	return 0;
    }
    
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 2; i <= n; i ++){
        	if(c1(i) || c2(i)){
        		printf("%d %d
    ", i, i - 1);
        	}
        	if(c3(i) || c4(i)){
        		printf("%d %d
    ", i, i);
        	}
        }
        return 0;
    }
    
    /*
     
     
     题意:
     
     类型:
     
     分析:
     
     优化:
     
     trick:
     
     数据:
     
     Sample Input
     
     Sample Output
     
     
     */
    

      

    J. Treasure Map

    设$f[i][j]$表示第$i$天位于$j$点的最大收益,暴力转移即可。

    时间复杂度$O(1000(n+m))$。

    #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 = 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, m;
    int g[N], d[N];
    vector<pair<int,int> >a[N];
    int f[N][N];
    int val(int p, int day)
    {
    	return max(0, g[p] - d[p] * (day - 1));
    }
    int main()
    {
    	while (~scanf("%d%d", &n, &m))
    	{
    		for (int i = 1; i <= n; ++i)
    		{
    			scanf("%d%d", &g[i], &d[i]);
    			a[i].clear();
    		}
    		for (int i = 1; i <= m; ++i)
    		{
    			int x, y, z;
    			scanf("%d%d%d", &x, &y, &z);
    			a[x].push_back({ y,z });
    			a[y].push_back({ x,z });
    		}
    		//printf("edge:%d %d
    ", a[1][0].first, a[1][0].second);
    		MS(f, -63);
    		f[1][1] = val(1, 1);
    		int ans = f[1][1];
    		for (int i = 1; i <= 1000; ++i)
    		{
    			for (int x = 1; x <= n; ++x)if(f[i][x] >= 0)
    			{
    				//
    				//printf("f[%d][%d] = %d
    ", i, x, f[i][x]);
    				//
    				for (auto it : a[x])
    				{
    					int y = it.first;
    					int z = it.second;
    					int day = min(i + z, 1005);
    					//
    					//printf("%d %d %d
    ", y, z, day);
    					//
    					gmax(f[day][y], f[i][x] + val(y, day));
    					gmax(ans, f[day][y]);
    				}
    			}
    		}
    		//for (int i = 1; i <= n; ++i)gmax(ans, f[1001][i]);
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    【数据】
    
    
    */
    

      

  • 相关阅读:
    前端与算法 leetcode 344. 反转字符串
    JavaScript闭包使用姿势指南
    前端与算法 leetcode 48. 旋转图像
    前端与算法 leetcode 36. 有效的数独
    前端与算法 leetcode 1. 两数之和
    前端与算法 leetcode 283. 移动零
    前端与编译原理 用js去运行js代码 js2run
    前端与算法 leetcode 66. 加一
    前端与算法 leetcode 350. 两个数组的交集 II
    前端与算法 leetcode 26. 删除排序数组中的重复项
  • 原文地址:https://www.cnblogs.com/clrs97/p/7855623.html
Copyright © 2011-2022 走看看