zoukankan      html  css  js  c++  java
  • 2017-2018 Northwestern European Regional Contest (NWERC 2017)

    A. Ascending Photo

    贪心增广。

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 1000000 + 10;
    vector<int> g[MAXN];
    int a[MAXN], b[MAXN], sz[MAXN], cnt[MAXN];
    bool mg[MAXN], vis[MAXN];
    int n, m;
    bool dfs(int u, int f = -1) {
      if (g[u].empty()) return false;
      for (auto &p: g[u]) if (p != f) {
        if (!vis[p + 1] || cnt[u + 1] == 1) {
          mg[p] = vis[p] = vis[p + 1] = 1;
          if (f != -1) mg[f] = 0;
          return true;
        }
      }
      for (auto &p: g[u]) if (p != f) {
        if (dfs(u + 1, p + 1)) {
          mg[p] = vis[p] = vis[p + 1] = 1;
          if (f != -1) mg[f] = 0;
          return true;
        }
      }
      return false;
    }
    int main(){
      scanf("%d", &n); m = 0;
      for (int i = 0, p(-1); i < n; ++ i) {
        int x; scanf("%d", &x);
        if (x == p) sz[m - 1] ++;
        else {
          p = x; a[m] = x;
          sz[m ++] = 1;
        }
      }
      n=m;
      for(int i=0;i<n;i++)b[i]=a[i];
      sort(b,b+n);
      for(int i=m=0;i<n;i++)if(i==0||b[i]>b[m-1])b[m++]=b[i];
      for (int i = 0; i < n; ++ i) {
        a[i] = lower_bound(b,b+m,a[i])-b;
        cnt[a[i]] ++;
      }
      for (int i = 0; i + 1 < n; ++ i) {
        if (a[i] + 1 == a[i + 1]) g[a[i]].push_back(i);
      }
      int ret = n;
      for (int i = m - 1; i >= 0; -- i) {
        if (dfs(i)) -- ret;
      }
      printf("%d", ret);
    }
    

      

    B. Boss Battle

    当$nleq 3$时显然$1$步就可以炸死。否则每次可以缩小一格,故答案为$n-2$。

    #include<cstdio>
    int n,ans;
    int main(){
    	scanf("%d",&n);
    	if(n<=3)ans=1;
    	else ans=n-2;
    	printf("%d",ans);
    }
    

      

    C. Connect the Dots

    留坑。

    D. Dunglish

    按题意模拟即可。

    #include<cstdio>
    #include<iostream>
    #include<map>
    #include<string>
    using namespace std;
    int n,m,i;
    string a[100];
    long long tot,co;
    map<string,int>f,g;
    map<string,string>o;
    int main(){
    	cin>>n;
    	for(i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	cin>>m;
    	while(m--){
    		string a,b,c;
    		cin>>a>>b>>c;
    		o[a]=b;
    		if(c[0]=='c')f[a]++;else g[a]++;
    	}
    	tot=1;
    	co=1;
    	for(i=1;i<=n;i++){
    		tot*=f[a[i]]+g[a[i]];
    		co*=f[a[i]];
    	}
    	if(tot==1){
    		for(i=1;i<=n;i++)cout<<o[a[i]]<<" "<<endl;
    		if(co==1){
    			printf("correct");
    		}else{
    			printf("incorrect");
    		}
    	}else{
    		printf("%lld correct
    ",co);
    		printf("%lld incorrect
    ",tot-co);
    	}
    }
    

      

    E. English Restaurant

    在最后新添$n$个容量$+infty$的桌子,表示离开餐馆,然后将桌子按容量排序。

    因为$期望=frac{总和}{方案数}$,所以可以同时DP出总和以及方案数。

    注意到最终占据的一定是若干个区间,首先预处理出$w[i][j]$表示只有$[i,j]$桌子被占据的总和以及方案数,枚举最后一张桌子转移。

    然后设$f[i][j]$表示$[i,n]$这些人占据了$[j,t]$这些桌子的总和以及方案数,利用前缀和优化转移。

    转移时需要用组合数体现顺序,时间复杂度$O(n^3)$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=210;
    int n,g,t,i,j,k,x,y,c[N];double C[N][N];
    struct P{
      double u,d;
      P(){}
      P(double _u,double _d){u=_u,d=_d;}
      P operator+(const P&b){return P(u*b.d+d*b.u,d*b.d);}
      P operator*(const P&b){return P(u+b.u,d+b.d);}
      void operator+=(const P&b){*this=*this+b;}
      void operator*=(const P&b){*this=*this*b;}
    }w[N][N],f[N][N],s[N][N],tmp;
    inline P cal(int l,int r){
      int x=min(g,l>0?c[l-1]:0),y=min(g,c[r]);
      return P(c[r]<N?(y*(y+1)-x*(x+1))/2:0,y-x);
    }
    int main(){
      scanf("%d%d%d",&n,&g,&t);
      for(i=0;i<n;i++)scanf("%d",&c[i]);
      sort(c,c+n);
      for(i=0;i<t;i++)c[n++]=N;
      for(C[0][0]=1,i=1;i<n+5;i++)for(C[i][0]=1,j=1;j<=i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
      for(j=0;j<n;j++){
        w[j][j]=cal(j,j);
        for(i=j-1;~i;i--)for(k=i;k<=j;k++){
          tmp=P(0,C[j-i][k-i])+cal(i,k);
          if(i<k)tmp+=w[i][k-1];
          if(j>k)tmp+=w[k+1][j];
          w[i][j]*=tmp;
        }
      }
      for(i=t-1;~i;i--)for(j=n-1;~j;j--)if(t-i<=n-j)f[i][j]=w[j][j+t-i-1];
      for(i=t-1;~i;i--)for(j=n-1;~j;j--){
        for(x=i+1;x<t;x++)f[i][j]*=P(0,C[t-i][t-x])+w[j][j+x-i-1]+s[x][j+x-i+1];
        s[i][j]=s[i][j+1]*f[i][j];
      }
      tmp=P(0,0);
      for(i=0;i<n;i++)tmp*=f[0][i];
      return printf("%.15f",tmp.u/tmp.d),0;
    }
    

      

    F. Factor-Free Tree

    限制条件等价于每个点和子树内每个点都互质,这说明在中序遍历上往前往后若干个互质。

    分解质因数,维护每个质因子最后一次出现的位置,即可求出$[l_i,r_i]$表示$i$与往前往后多少范围内都互质。

    按中序遍历从左往右依次考虑每个点,用一个栈维护之前部分的树的最右链,对于$i$,先将它往下挂,然后尝试往上浮动,因为$r$越大的点越靠近根更优,除非$l$太大以至于不能覆盖住左边的子树。

    一旦一个点的父亲确定,那么它的超过父亲的$r$的部分是毫无用处的,将$r$直接和父亲取$min$。

    如此一来,每条链上满足$r$递减,故直接暴力退栈直到找到合适的位置即可。

    构造部分时间复杂度为$O(n)$。

    #include<stdio.h>
    #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 = 1000010, M = 10000010, 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,i,j;
    int v[M],p[N],tot,last[M];
    int a[N],left[N],right[N];
    struct S
    {
    	int l, r, rpow;
    }s[N];
    int fa[N];
    int main()
    {
    	for(i=2;i<M;i++){
    		if(!v[i]){
    			p[tot++]=i;
    			v[i]=i;
    		}
    		for(j=0;j<tot&&i*p[j]<M;j++){
    			v[i*p[j]]=p[j];
    			if(i%p[j]==0)break;
    		}
    	}
    	while(~scanf("%d",&n))
    	{
    		for(i=1;i<=n;i++)scanf("%d",&a[i]);
    		for(i=2;i<M;i++)last[i]=0;
    		for(i=1;i<=n;i++){
    			left[i]=0;
    			int x=a[i];
    			while(x>1){
    				//printf("! %d %d
    ",i,v[x]);
    				left[i]=max(left[i],last[v[x]]);
    				x/=v[x];
    			}
    			left[i]++;
    			x=a[i];
    			while(x>1){
    				last[v[x]]=i;
    				x/=v[x];
    			}
    		}
    		for(i=2;i<M;i++)last[i]=n+1;
    		for(i=n;i;i--){
    			right[i]=n+1;
    			int x=a[i];
    			while(x>1){
    				right[i]=min(right[i],last[v[x]]);
    				x/=v[x];
    			}
    			right[i]--;
    			x=a[i];
    			while(x>1){
    				last[v[x]]=i;
    				x/=v[x];
    			}
    		}
    		//for(i=1;i<=n;i++)printf("%d [%d,%d]
    ",i,left[i],right[i]);
    
    		int top = 0;
    		s[0].rpow = inf;
    		bool flag = 1;
    		for(int i = 1; i <= n; ++i)
    		{
    			fa[i] = 0;
    			s[top + 1].r = 0;
    			int lft = i;
    			while(left[i] <= s[top].l && s[top].rpow <= right[i])
    			{
    				gmin(lft, s[top].l);
    				--top;
    			}
    			fa[s[top + 1].r] = i;
    			fa[i] = s[top].r;
    			++top;
    			s[top].l = lft;
    			s[top].r = i;
    			s[top].rpow = min(right[i], s[top - 1].rpow);
    			//printf("i: %d l = %d r = %d rpow = %d
    ", i, s[top].l, s[top].r, s[top].rpow);
    			if(s[top - 1].rpow < i)
    			{
    				flag = 0;
    				//printf("i = %d s[top - 1].rpow = %d
    ", i, s[top - 1].rpow);
    			}
    		}
    		if(!flag)puts("impossible");
    		else
    		{
    			for(int i = 1; i <= n; ++i)printf("%d ", fa[i]);
    			puts("");
    		}
    	}
    	return 0;
    }
    
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    G. Glyph Recognition

    枚举形状,然后二分求出半径。

    #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 = 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;
    const double eps = 1e-8;
    inline int sgn(double x) {return fabs(x) < eps ? 0 : (x < 0 ? -1 : 1);}
    inline double sqr(double x){return x * x;}
    
    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));
        }
    } ;
    
    double det(const point &a, const point &b)
    {
        return a.x * b.y - a.y * b.x;
    }
    double dot(const point &a, const point &b)
    {
        return a.x * b.x + a.y * b.y;
    }
    double dist(const point &a, const point &b)
    {
        return (a - b).norm();
    }
    point rotate_point(const point &p, double A)
    {
        double tx = p.x, ty = p.y;
        return point(tx * cos(A) - ty * sin(A), tx * sin(A) + ty * cos(A));
    }
    bool PointOnSegment(point p, point s, point t)
    {
        return sgn(det(p - s, t - s)) == 0 && sgn(dot(p - s, p - t)) <= 0;
    }
    struct polygon
    {
        int n;
        point a[N];
        polygon(){}
        double area(){
            double sum = 0;
            a[n] = a[0];
            for(int i = 0; i < n; i ++) sum += det(a[i + 1], a[i]);
            return sum / 2;
        }
        int Point_In(point t){
            int num = 0, i, d1, d2, k;
            a[n] = a[0];
            for(i = 0; i < n; i ++){
                if(PointOnSegment(t, a[i], a[i + 1])) return 2;
                k = sgn(det(a[i + 1] - a[i], t - a[i]));
                d1 = sgn(a[i].y - t.y);
                d2 = sgn(a[i + 1].y - t.y);
                if(k > 0 && d1 <= 0 && d2 > 0) num ++;
                if(k < 0 && d2 <= 0 && d1 > 0) num --;
            }
            return num != 0;
        }
    }c;
    
    point p[N];
    const double PI = acos(-1.0);
    void make(int n, double r)
    {
        double ang = PI * 2.0 / n;
        c.a[0] = point(r, 0);
        for(int i = 1; i < n; i ++){
            c.a[i] = rotate_point(c.a[0], PI * 2 - ang * i);
        }
    }
    
    int n;
    
    bool check()
    {
        for(int i = 0; i < n; i ++){
            if(c.Point_In(p[i]) == 0) return 0;
        }
        return 1;
    }
    
    bool check2()
    {
        for(int i = 0; i < n; i ++){
            if(c.Point_In(p[i]) == 1) return 0;
        }
        return 1;
    }
    const double INF = 1e9;
    int main()
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i ++){
            scanf("%lf%lf", &p[i].x, &p[i].y);
        }
        double k = 0;
        int ans;
        for(int i = 3; i <= 8; i ++){
            c.n = i;
            double l = 0, r = INF;
            for(int tim = 1; tim <= 1000; tim ++){
                double mid = (l + r) / 2;
                make(i, mid);
                if(check()) r = mid;
                else l = mid;
            }
            double out = c.area();
            l = 0, r = INF;
            for(int tim = 1; tim <= 1000; tim ++){
                double mid = (l + r) / 2;
                make(i, mid);
                if(check2()) l = mid;
                else r = mid;
            }
            double in = c.area();
            double tmp = in / out;
            if(tmp > k){
                k = tmp;
                ans = i;
            }
        }
        printf("%d %.10f
    ", ans, k);
    }
    
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    H. High Score

    因为平方增长较快,所以全部给某个数是最优的,但在小数据下不一定成立,故小数据暴力枚举即可。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int K=1000;
    int T;ll a,b,c,d,i,j,k,ans;
    inline ll cal(ll a,ll b,ll c){return a*a+b*b+c*c+min(a,min(b,c))*7;}
    int main(){
    	cin>>T;
    	while(T--){
    		cin>>a>>b>>c>>d;
    		ans=0;
    		for(i=0;i<=d&&i<=K;i++)for(j=0;i+j<=d&&j<=K;j++){
    			k=d-i-j;
    			ans=max(ans,cal(a+i,b+j,c+k));
    			ans=max(ans,cal(a+i,b+k,c+j));
    			ans=max(ans,cal(a+k,b+i,c+j));
    		}
    		ans=max(ans,cal(a+d,b,c));
    		ans=max(ans,cal(a,b+d,c));
    		ans=max(ans,cal(a,b,c+d));
    		cout<<ans<<endl;
    	}
    }
    

      

    I. Installing Apps

    每个应用可以看成会先占用$max(d,s)$的空间,然后释放$max(d,s)-s$的空间。

    假设全部应用都要安装,那么按照释放空间的大小从大到小安装最优。

    如此排序之后设$f[i][j]$表示考虑前$i$个应用,剩余空间为$j$时最多安装几个应用即可。

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

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=505,M=10010;
    int n,m,i,j,x,f[N][M],g[N][M],w[N][M],q[N],cnt;
    struct P{int p,w,t;}a[N];
    inline bool cmp(const P&a,const P&b){return a.t>b.t;}
    int main(){
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=n;i++){
    		int d,s;
    		scanf("%d%d",&d,&s);
    		a[i].p=i;
    		a[i].w=max(d,s);
    		a[i].t=a[i].w-s;
    	}
    	sort(a+1,a+n+1,cmp);
    	for(i=0;i<=n;i++)for(j=0;j<=m;j++)f[i][j]=-M;
    	f[0][m]=0;
    	for(i=1;i<=n;i++){
    		for(j=0;j<=m;j++){
    			f[i][j]=f[i-1][j];
    			g[i][j]=j;
    			w[i][j]=0;
    		}
    		for(j=0;j<=m;j++)if(f[i-1][j]>=0){
    			if(j<a[i].w)continue;
    			if(f[i-1][j]+1>f[i][j-a[i].w+a[i].t]){
    				f[i][j-a[i].w+a[i].t]=f[i-1][j]+1;
    				g[i][j-a[i].w+a[i].t]=j;
    				w[i][j-a[i].w+a[i].t]=a[i].p;
    			}
    		}
    	}
    	for(i=x=0;i<=m;i++)if(f[n][i]>f[n][x])x=i;
    	printf("%d
    ",f[n][x]);
    	for(i=n;i;i--){
    		if(w[i][x])q[++cnt]=w[i][x];
    		x=g[i][x];
    	}
    	for(i=cnt;i;i--)printf("%d ",q[i]);
    }
    

      

    J. Juggling Troupe

    对于$i$处的$2$,往前往后找到第一个$0$的位置$l,r$,将$l$和$r$赋值为$1$,然后将$l+r-i$赋值为$0$即可。

    set维护,时间复杂度$O(nlog n)$。

    #include<cstdio>
    #include<set>
    #include<cstring>
    using namespace std;
    const int N=1000010;
    set<int>T;int n,i,x;char a[N];
    int main(){
      scanf("%s",a+1);
      n=strlen(a+1);
      T.insert(0);
      T.insert(n+1);
      for(i=1;i<=n;i++)if(a[i]=='0')T.insert(i);
      for(i=1;i<=n;i++)if(a[i]=='2'){
        set<int>::iterator r=T.lower_bound(i),l=r;
        l--;
        x=*l+*r-i;
        if(*l>0)T.erase(l);
        if(*r<=n)T.erase(r);
        T.insert(x);
      }
      for(i=1;i<=n;i++)a[i]='1';
      for(set<int>::iterator it=T.begin();it!=T.end();it++)a[*it]='0';
      for(i=1;i<=n;i++)putchar(a[i]);
    }
    

      

    K. Knockout Tournament

    对于$1$,要让他的对手尽量弱小,而对于其他人,要让他的对手和他水平尽量接近,以降低他的胜率。

    故将$1$看作$0$水平后从小到大排序,相邻的配对即可。

    然后计算概率的时候只需要暴力枚举两边的胜者,两个点只会在lca处被计算,故时间复杂度为$O(n^2)$。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    typedef pair<int,double>P;
    const int N=8200;
    int n,m,i,j,a[N],start;
    vector<P>f[N];
    inline double win(int x,int y){
    	return 1.0*a[x]/(a[x]+a[y]);
    }
    inline void cal(int x){
    	int l=x<<1,r=x<<1|1;
    	for(int _=0;_<2;_++){
    		for(vector<P>::iterator i=f[l].begin();i!=f[l].end();i++){
    			int A=i->first;
    			double B=0;
    			for(vector<P>::iterator j=f[r].begin();j!=f[r].end();j++){
    				B+=win(A,j->first)*j->second;
    			}
    			f[x].push_back(P(A,B*i->second));
    		}
    		swap(l,r);
    	}
    }
    int id[N],cnt;
    void dfs(int x){
    	if((x<<1)>m){
    		id[++cnt]=x;
    		//printf("%d %d
    ",cnt,x);
    	}
    	if((x<<1)<=m)dfs(x<<1);
    	if((x<<1|1)<=m)dfs(x<<1|1);
    }
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	a[0]=a[1];
    	a[1]=0;
    	sort(a+1,a+n+1);
    	a[1]=a[0];
    	m=n*2-1;
    	start=m-n+1;
    	dfs(1);
    	for(i=1;i<=n;i++){
    		int x=id[n-i+1];
    		f[x].push_back(P(i,1));
    	}
    	for(i=start-1;i;i--){
    		cal(i);
    	}
    	for(i=0;i<f[1].size();i++)if(f[1][i].first==1){
    		printf("%.10f",f[1][i].second);
    	}
    }
    

      

  • 相关阅读:
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    flowable 获取当前任务流程图片的输入流
    最新 接口api插件 Swagger3 更新配置详解
    springboot 集成 activiti 流程引擎
    java 在线考试系统源码 springboot 在线教育 视频直播功能 支持手机端
    阿里 Nacos 注册中心 配置启动说明
    springboot 集成外部tomcat war包部署方式
    java 监听 redis 过期事件
    springcloudalibaba 组件版本关系
    java WebSocket 即时通讯配置使用说明
  • 原文地址:https://www.cnblogs.com/clrs97/p/7936483.html
Copyright © 2011-2022 走看看