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&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    【数据】
    
    
    */
    

      

  • 相关阅读:
    配置虚拟主机并更改Apache默认解析路径
    在ListView中实现排序
    petshop4.0 具体解释之中的一个(系统架构设计)
    学习笔记之TCP/IP协议分层与OSI參考模型
    cidaemon.exe进程cpu占用率高及关闭cidaemon.exe进程方法
    cmake 学习笔记(一)
    标准差(standard deviation)和标准误差(standard error)你能解释清楚吗?
    Web.xml配置具体解释之context-param
    福克斯:悲观?乐观?就看你与世界怎么互动
    Android 服务类Service 的具体学习
  • 原文地址:https://www.cnblogs.com/clrs97/p/7855623.html
Copyright © 2011-2022 走看看