zoukankan      html  css  js  c++  java
  • 2017-2018 ACM-ICPC, Central Europe Regional Contest (CERC 17)

    A. Assignment Algorithm

    按题意模拟即可。

    #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 = 60, 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, lft, rgt;
    int empty[N];
    char s[N][20];
    int rk[10][2];
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	lft = n * 4; rgt = n * 4;
    	for(int i = 1; i <= n + 3; i ++){
    		empty[i] = 9;
    		scanf("%s", s[i] + 1);
    		for(int j = 1; j <= 11; j ++){
    			if(s[i][j] == '#'){
    				empty[i] --;
    				if(j <= 5) lft --;
    				else if(j >= 7) rgt --;
    			}
    		}
    	}
    	for(int ch = 0; ch < m; ch ++){
                //printf("%d %d %d
    ", ch, lft, rgt);
    		int tmpe = 0, o = 0, dis = 100;
    		if(ch == 13){
                int go = 1;
    		}
    		if(empty[2]){
    			tmpe = empty[2];
    			o = 2;
    		}
    		if(empty[n / 2 + 3] > tmpe){
    			tmpe = empty[n / 2 + 3];
    			o = n / 2 + 3;
    		}
    		if(o == 0){
    			for(int i = 3; i <= n / 2 + 1; i ++){
    				if(empty[i] > tmpe){
    					tmpe = empty[i];
    					o = i;
    					dis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2)));
    				}
    				else if(empty[i] == tmpe){
    					int tmpdis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2)));
    					if(tmpdis < dis){
    						dis = tmpdis;
    						o = i;
    					}
    				}
    			}
    			for(int i = n / 2 + 4; i <= n + 2; i ++){
    				if(empty[i] > tmpe){
    					tmpe = empty[i];
    					o = i;
    					dis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2)));
    				}
    				else if(empty[i] == tmpe){
    					int tmpdis = min(abs(i - n - 3), min(abs(i - 1), abs(i - n / 2 - 2)));
    					if(tmpdis < dis){
    						dis = tmpdis;
    						o = i;
    					}
    				}
    			}
    		}
    		empty[o] --;
    
    		rk[0][0] = 5, rk[0][1] = 7;
    		rk[1][0] = 3, rk[1][1] = 9;
    		rk[2][0] = 1, rk[2][1] = 11;
    		rk[3][0] = 6, rk[3][1] = 6;
    		rk[4][0] = 2, rk[4][1] = 10;
    
    		for(int i = 0; i <= 4; i ++){
    			if(s[o][rk[i][0]] == '-' || s[o][rk[i][1]] == '-'){
    				if(i == 3){
                        s[o][6] = ch + 'a';
                        break;
    				}
    				if(s[o][rk[i][0]] == '-' && s[o][rk[i][1]] == '-'){
    					if(lft >= rgt) s[o][rk[i][0]] = ch + 'a', lft --;
    					else s[o][rk[i][1]] = ch + 'a', rgt --;
    				}
    				else if(s[o][rk[i][0]] == '-'){
    					s[o][rk[i][0]] = ch + 'a', lft --;
    				}
    				else {s[o][rk[i][1]] = ch + 'a', rgt --;}
    				break;
    			}
    		}
    	}
    
    	for(int i = 1; i <= n + 3; i ++){
    		printf("%s
    ", s[i] + 1);
    	}
    	return 0;
    }
    
    /*
    2 17
    ...........
    ---.#--.---
    ...........
    ---.---.---
    ...........
    
    
    6 26
    ...........
    ---.---.###
    #-#.---.---
    ---.###.---
    ...........
    ---.###.---
    #--.#-#.--#
    #--.--#.#-#
    ...........
    
    
    
    0 17 12
    1 16 12
    2 15 12
    3 15 11
    4 15 10
    5 14 10
    6 13 10
    7 12 10
    8 12 9
    9 12 9
    10 11 9
    11 10 9
    12 10 8
    13 9 8
    14 8 8
    15 8 7
    16 8 6
    17 7 6
    18 7 5
    19 6 5
    20 5 5
    21 4 5
    22 4 4
    23 4 3
    24 4 2
    25 4 2
    ...........
    gke.aic.###
    #-#.mzo.r-v
    t-n.###.p-x
    ...........
    fjb.###.dlh
    #-s.#-#.w-#
    #-u.qy#.#-#
    ...........
    
    
    */
    
    /*
    【trick&&吐槽】
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    B. Buffalo Barricades

    首先通过扫描线求出最终的图中每个点属于哪个区域,以及包含每个区域的最小区域。

    然后倒着处理每个询问,依次删掉每个栅栏,也就是将区域的点数合并,并查集维护。

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

    #include<cstdio>
    #include<algorithm>
    #include<set>
    using namespace std;
    typedef pair<int,int>P;
    const int N=600010;
    int n,m,ce,i,x,y,z,v[N],f[N],g[N],ans[N];set<P>T;
    struct E{int x,y,t;E(){}E(int _x,int _y,int _t){x=_x,y=_y,t=_t;}}e[N];
    inline bool cmp(const E&a,const E&b){
      if(a.y!=b.y)return a.y>b.y;
      return a.x<b.x;
    }
    inline int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
    inline void merge(int x,int y){
      x=F(x),y=F(y);
      if(x==y)return;
      f[x]=y,v[y]+=v[x];
    }
    int main(){
      scanf("%d",&n);
      for(i=1;i<=n;i++){
        scanf("%d%d",&x,&y);
        x<<=1,y<<=1;
        e[++ce]=E(x,y,0);
      }
      scanf("%d",&m);
      for(i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        x<<=1,y<<=1;
        x++,y++;
        e[++ce]=E(x,y,i);
        f[i]=i;
      }
      sort(e+1,e+ce+1,cmp);
      for(i=1;i<=ce;i++){
        x=e[i].x,z=e[i].t;
        if(z){
          T.insert(P(x,z));
          set<P>::iterator it=T.find(P(x,z)),k=it;
          k++;
          if(k!=T.end())g[z]=k->second;
          while(1){
            k=T.find(P(x,z));
            if(k==T.begin())break;
            k--;
            if(k->second<z)break;
            T.erase(k);
          }
        }else{
          set<P>::iterator it=T.lower_bound(P(x,0));
          if(it!=T.end())v[it->second]++;
        }
      }
      for(i=m;i;i--){
        ans[i]=v[F(i)];
        if(g[i])merge(i,g[i]);
      }
      for(i=1;i<=m;i++)printf("%d
    ",ans[i]);
    }
    

      

    C. Cumulative Code

    留坑。

    D. Donut Drone

    LCT维护环套树,在根与根的父亲处断开。

    对于link操作,若成环则无视。

    对于cut操作,删边之后再将环边link即可。

    对于查询操作,首先求出与环末端点的LCA,这就是进入环的点,剩下的部分模环长后分两段走即可。

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

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=2010,M=N*N;
    int n,m,a[M],f[M],son[M][2],size[M];
    int v[N][N],id[N][N],tot,loc[M][2],O;
    int i,j,k,x,y,z;char op[100];
    inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
    inline void up(int x){size[x]=size[son[x][0]]+size[son[x][1]]+1;}
    inline void rotate(int x){
    	int y=f[x],w=son[y][1]==x;
    	son[y][w]=son[x][w^1];
    	if(son[x][w^1])f[son[x][w^1]]=y;
    	if(f[y]){
    		int z=f[y];
    		if(son[z][0]==y)son[z][0]=x;
    		else if(son[z][1]==y)son[z][1]=x;
    	}
    	f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
    }
    inline void splay(int x){
    	while(!isroot(x)){
    		int y=f[x];
    		if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
    		rotate(x);
    	}
    	up(x);
    }
    inline int access(int x){
    	int y=0;
    	for(;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);
    	return y;
    }
    inline int lca(int x,int y){
    	access(x);
    	return access(y);
    }
    inline int root(int x){
    	access(x);
    	splay(x);
    	while(son[x][0])x=son[x][0];
    	splay(x);
    	return x;
    }
    inline void link(int x,int y){
    	if(root(x)!=root(y))splay(x),f[x]=y,access(x);
    }
    inline void cut(int x,int y){
    	int u=root(x);
    	if(u==x)return;
    	access(x);
    	splay(x);
    	f[son[x][0]]=0;
    	son[x][0]=0;
    	up(x);
    	link(u,a[u]);
    }
    inline int dis(int x){
    	access(x);
    	splay(x);
    	return size[son[x][0]];
    }
    inline int goup(int x,int k){
    	k=dis(x)-k+1;
    	access(x);
    	splay(x);
    	while(1){
    		int t=size[son[x][0]]+1;
    		if(k==t)return x;
    		if(k<t)x=son[x][0];else k-=t,x=son[x][1];
    	}
    }
    inline int moveup(int x,int k){
    	x=goup(x,k);
    	splay(x);
    	return x;
    }
    inline int simulate(int x,int k){
    	int u=root(x),y=a[u],z=lca(x,y);
    	int A=dis(x),B=dis(y),C=dis(z);
    	if(A>C){
    		int t=min(A-C,k);
    		k-=t;
    		x=moveup(x,t);
    	}
    	k%=B+1;
    	if(!k)return x;
    	int t=min(dis(x),k);
    	k-=t;
    	x=moveup(x,t);
    	if(!k)return x;
    	x=y;
    	k--;
    	if(!k)return x;
    	return moveup(x,k);
    }
    inline int getnxt(int o){
    	int x=loc[o][0],y=loc[o][1];
    	y++;
    	y%=m;
    	int mx=-1,w=0;
    	for(int i=x-1;i<=x+1;i++){
    		int nx=(i%n+n)%n;
    		if(v[nx][y]>mx){
    			mx=v[nx][y];
    			w=id[nx][y];
    		}
    	}
    	return w;
    }
    inline void check(int x,int y){
    	x%=n,y%=m;
    	x+=n,y+=m;
    	x%=n,y%=m;
    	int o=id[x][y];
    	int now=getnxt(o);
    	if(a[o]!=now){
    		cut(o,a[o]);
    		a[o]=now;
    		link(o,a[o]);
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(i=0;i<n;i++)for(j=0;j<m;j++){
    		scanf("%d",&v[i][j]);
    		id[i][j]=++tot;
    		loc[tot][0]=i;
    		loc[tot][1]=j;
    	}
    	for(i=1;i<=tot;i++)size[i]=1;
    	for(i=1;i<=tot;i++){
    		a[i]=getnxt(i);
    		link(i,a[i]);
    	}
    	O=id[0][0];
    	int _;
    	scanf("%d",&_);
    	while(_--){
    		scanf("%s",op);
    		if(op[0]=='c'){
    			scanf("%d%d%d",&x,&y,&z);
    			x--,y--;
    			v[x][y]=z;
    			check(x-1,y-1);
    			check(x,y-1);
    			check(x+1,y-1);
    		}else{
    			scanf("%d",&k);
    			O=simulate(O,k);
    			printf("%d %d
    ",loc[O][0]+1,loc[O][1]+1);
    		}
    	}
    }
    /*
    3 4
    10 20 30 40
    50 60 70 80
    90 93 95 99
    3
    move 4
    change 2 1 100
    move 4
    */
    

      

    E. Embedding Enumeration

    留坑。

    F. Faulty Factorial

    显然要修改的数与$n$相差不超过$P$,枚举每个数分类讨论即可。

    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    typedef long long ll;
    const int N=10000010;
    ll n;
    int P,R,i;
    int s[N],inv[N];
    inline ll po(ll a,ll b,ll P){
    	ll t=1;
    	for(;b;b>>=1,a=a*a%P)if(b&1)t=t*a%P;
    	return t;
    }
    struct Num{
    	ll a,b;
    	Num(){a=1,b=0;}
    	Num(ll _a,ll _b){a=_a,b=_b;}
    	Num operator*(Num x){return Num(a*x.a%P,b+x.b);}
    	Num operator/(Num x){return Num(a*inv[x.a]%P,b-x.b);}
    }res;
    Num cal(ll n){
    	return n?Num(s[n%P]*po(s[P],n/P,P)%P,n/P)*cal(n/P):Num(1,0);
    }
    inline Num ask(ll n){
    	ll b=0;
    	while(n%P==0)n/=P,b++;
    	return Num(n%P,b);
    }
    void ok(ll a,ll b){
    	printf("%lld %lld",a,b);
    	exit(0);
    }
    int main(){
    	scanf("%lld%d%d",&n,&P,&R);
    	for(i=s[0]=1;i<P;i++)s[i]=1LL*s[i-1]*i%P;
    	s[P]=s[P-1];
    	for(inv[0]=inv[1]=1,i=2;i<P;i++)inv[i]=1LL*(P-inv[P%i])*(P/i)%P;
    	res=cal(n);
    	ll W=1LL*R*inv[res.a]%P;
    	for(ll x=n;x>1&&x>n-P-10;x--){
    		ll A=x,B=0;
    		while(A%P==0)A/=P,B++;
    		if(res.b>B){
    			if(R)continue;
    			ok(x,1);
    		}else{
    			if(R){
    				ll y=A%P*W%P;
    				if(y<x)ok(x,y);
    			}else{
    				if(P<x)ok(x,P);
    			}
    		}
    	}
    	puts("-1 -1");
    }
    

      

    G. Gambling Guide

    设$e_x$表示$x$到$n$的最优期望次数,则$e_n=0,e_x=frac{summin(e_x,e_y)}{deg_x}+1$。

    每次用堆取出$e_x$最小的$x$,更新周围一圈点即可。

    时间复杂度$O(mlog m)$。

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    typedef pair<double,int>P;
    const int N=300010;
    const double inf=1e100;
    int n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
    double f[N],s[N];
    int d[N],c[N];
    bool vis[N];
    priority_queue<P,vector<P>,greater<P> >q;
    inline void add(int x,int y){
    	v[++ed]=y;nxt[ed]=g[x];g[x]=ed;
    	d[x]++;
    }
    inline void ext(int x){
    	double now=(s[x]+d[x])/c[x];
    	if(now<f[x]){
    		f[x]=now;
    		q.push(P(now,x));
    	}
    }
    inline void up(int x,double y){
    	vis[x]=1;
    	for(int i=g[x];i;i=nxt[i]){
    		int u=v[i];
    		if(vis[u])continue;
    		c[u]++;
    		s[u]+=y;
    		ext(u);
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	while(m--){
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		add(y,x);
    	}
    	for(i=1;i<n;i++)f[i]=inf;
    	q.push(P(0,n));
    	while(!q.empty()){
    		P t=q.top();q.pop();
    		if(vis[t.second])continue;
    		up(t.second,t.first);
    	}
    	printf("%.10f",f[1]);
    }
    

      

    H. Hidden Hierarchy

    按题意模拟即可。

    #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 L = 1e5 + 10, 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 T;
    char s[L];
    map<string, set<string> >mop;
    map<string, int>v;
    void dfs1(string x)
    {
        for(auto y : mop[x])
        {
            dfs1(y);
            v[x] += v[y];
        }
    }
    void dfs2(string x)
    {
        if(!mop[x].size())
        {
            printf("%c %s %d
    ", ' ', x.c_str(), v[x]);
            return;
        }
        bool flag = 0;
        for(auto y : mop[x])
        {
            if(v[y] >= T)flag = 1;
        }
        if(!flag)
        {
            printf("%c %s %d
    ", '+', x.c_str(), v[x]);
            return;
        }
        else
        {
            printf("%c %s %d
    ", '-', x.c_str(), v[x]);
            for(auto y : mop[x])
            {
                dfs2(y);
            }
        }
    }
    int main()
    {
        int n;
    while(~scanf("%d", &n))
    {
        mop.clear();v.clear();
        for(int i = 1; i <= n; ++i)
        {
            int val;
            scanf("%s%d", s, &val);
            string fa = "#";
            for(int i = 0; s[i]; ++i)if(s[i] == '/')
            {
                char tmp = s[i + 1];
                s[i + 1] = 0;
                mop[fa].insert(s);
                fa = s;
                s[i + 1] = tmp;
            }
            v[fa] += val;
        }
        string rt = "/";
        dfs1(rt);
        //
        //printf("%d
    ", v[rt]);
        //
        scanf("%d", &T);
        dfs2(rt);
    }
    	return 0;
    }
    /*
    【trick&&吐槽】
    2
    /a/a/a            100
    /b.txt            99
    200
    
    
    【题意】
    
    
    【分析】
    
    
    【时间复杂度&&优化】
    
    
    */
    

      

    I. Intrinsic Interval

    若一个区间$[l,r]$满足$max-min=r-l$,则值域连续。

    也就是$max-min-r+l=0$,注意到$max-min-r+lgeq 0$恒成立,故为了在合法的情况下区间长度最短,应该满足$v=(max-min-r+l)n+r-l$最小,区间长度即为$vmod n$。

    利用单调栈求出每个数作为最值的范围,对应$v$的矩形加。

    从左往右考虑每个$l$,用线段树维护每个$r$的$v$,对于一个询问,答案即为区间历史最小值,线段树维护即可。

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

    #include<cstdio>
    #include<algorithm>
    #define lc x<<1
    #define rc x<<1|1
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>P;
    const int N=100010,M=262150,E=500010;
    const ll inf=1LL<<60;
    int n,Q,i,j,a[N],t,q[N],l[N],r[N];
    int ga[N],gd[N],gq[N],ed,vl[E],vr[E],nxt[E];ll w[E];
    P ans[N];
    ll m[M],hm[M],d[M],hd[M];
    ll fin;
    int pos;
    inline void Min(ll&a,ll b){a>b?(a=b):0;}
    inline void hdoa(int x,ll v){
    	Min(hm[x],m[x]+v);
    	Min(hd[x],d[x]+v);
    }
    inline void doa(int x,ll v){
    	Min(hm[x],m[x]+=v);
    	Min(hd[x],d[x]+=v);
    }
    inline void pb(int x){
    	if(hd[x])hdoa(lc,hd[x]),hdoa(rc,hd[x]),hd[x]=0;
    	if(d[x])doa(lc,d[x]),doa(rc,d[x]),d[x]=0;
    }
    inline void up(int x){
    	m[x]=min(m[lc],m[rc]);
    	Min(hm[x],min(hm[lc],hm[rc]));
    }
    void build(int x,int a,int b){
    	if(a==b){
    		hm[x]=m[x]=-1LL*a*(n-1);
    		return;
    	}
    	int mid=(a+b)>>1;
    	build(x<<1,a,mid);
    	build(x<<1|1,mid+1,b);
    	up(x);
    }
    void dfs(int x,int a,int b){
    	if(a==b){
    		hm[x]=m[x];
    		return;
    	}
    	pb(x);
    	int mid=(a+b)>>1;
    	dfs(x<<1,a,mid);
    	dfs(x<<1|1,mid+1,b);
    	m[x]=min(m[lc],m[rc]);
    	hm[x]=min(hm[lc],hm[rc]);
    }
    void add(int x,int f,int t,int qf,int qt,ll v){
    	if(qf<=f&&t<=qt){doa(x,v);return;}
    	pb(x);
    	int mid=(f+t)>>1;
    	if(qf<=mid)add(lc,f,mid,qf,qt,v);
    	if(qt>mid)add(rc,mid+1,t,qf,qt,v);
    	up(x);
    }
    
    inline void addedge(int&x,int l,int r,ll z){
    	vl[++ed]=l;
    	vr[ed]=r;
    	w[ed]=z;
    	nxt[ed]=x;
    	x=ed;
    }
    inline void ext(int xl,int xr,int yl,int yr,ll w){
    	//printf("%d %d %d %d %lld
    ",xl,xr,yl,yr,w);
    	if(w>=0){
    		addedge(ga[xl],yl,yr,w);
    		addedge(gd[xr+1],yl,yr,-w);
    	}else{
    		addedge(gd[xl],yl,yr,w);
    		addedge(ga[xr+1],yl,yr,-w);
    	}
    }
    
    void ask(int x,int a,int b,int c,int d){
    	if(c<=a&&b<=d){
    		Min(fin,hm[x]);
    		return;
    	}
    	pb(x);
    	int mid=(a+b)>>1;
    	if(c<=mid)ask(x<<1,a,mid,c,d);
    	if(d>mid)ask(x<<1|1,mid+1,b,c,d);
    }
    void getpos(int x,int a,int b,int c,int d){
    	if(pos)return;
    	if(hm[x]>fin)return;
    	if(a==b){
    		pos=a;
    		return;
    	}
    	pb(x);
    	int mid=(a+b)>>1;
    	if(c<=mid)getpos(x<<1,a,mid,c,d);
    	if(d>mid)getpos(x<<1|1,mid+1,b,c,d);
    }
    
    inline P query(int l,int r){
    	fin=inf;
    	ask(1,1,n,r,n);
    	//printf("! %d %d %lld
    ",l,r,fin);
    	pos=0;
    	getpos(1,1,n,r,n);
    	return P(pos-fin%n,pos);
    }
    
    int main(){
    	//(ma-mi-r+l)*n+r-l
    	//ma*n-mi*n-r*(n-1)+l*(n-1)
    	scanf("%d",&n);
    	for(i=1;i<=n;i++)scanf("%d",&a[i]);
    	scanf("%d",&Q);
    	for(i=1;i<=Q;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		addedge(gq[x],i,y,0);
    	}
    	
    	for(q[t=0]=0,i=1;i<=n;i++){
    		while(t&&a[i]>a[q[t]])t--;
    		l[i]=q[t]+1;
    		q[++t]=i;
    	}
    	for(q[t=0]=n+1,i=n;i;i--){
    		while(t&&a[i]>a[q[t]])t--;
    		r[i]=q[t]-1;
    		q[++t]=i;
    	}
    	for(i=1;i<=n;i++)ext(l[i],i,i,r[i],1LL*a[i]*n);
    	
    	for(q[t=0]=0,i=1;i<=n;i++){
    		while(t&&a[i]<a[q[t]])t--;
    		l[i]=q[t]+1;
    		q[++t]=i;
    	}
    	for(q[t=0]=n+1,i=n;i;i--){
    		while(t&&a[i]<a[q[t]])t--;
    		r[i]=q[t]-1;
    		q[++t]=i;
    	}
    	for(i=1;i<=n;i++)ext(l[i],i,i,r[i],-1LL*a[i]*n);
    	
    	build(1,1,n);
    	for(i=1;i<=n;i++){
    		add(1,1,n,1,n,n-1);
    		for(j=ga[i];j;j=nxt[j]){
    			add(1,1,n,vl[j],vr[j],w[j]);
    		}
    		for(j=gd[i];j;j=nxt[j]){
    			add(1,1,n,vl[j],vr[j],w[j]);
    		}
    		if(i==1)dfs(1,1,n);
    		for(j=gq[i];j;j=nxt[j]){
    			ans[vl[j]]=query(i,vr[j]);
    		}
    	}
    	
    	for(i=1;i<=Q;i++)printf("%d %d
    ",ans[i].first,ans[i].second);
    }
    /*
    7
    3 1 7 5 6 4 2
    3
    3 6
    7 7
    1 3
    
    
    7
    3 1 7 5 6 4 2
    3
    3 6
    7 7
    1 3
    1 1 1 2 21
    2 2 2 2 7
    1 3 3 7 49
    4 4 4 4 35
    4 5 5 7 42
    6 6 6 7 28
    7 7 7 7 14
    1 1 1 1 -21
    1 2 2 7 -7
    3 3 3 3 -49
    3 4 4 5 -35
    5 5 5 5 -42
    3 6 6 6 -28
    3 7 7 7 -14
    ! 1 3 -12
    ! 3 6 -30
    ! 7 7 -36
    8 6
    8 7
    8 3
    
    */
    

      

    J. Justified Jungle

    枚举每个$k$,那么剩下每个子树大小均为$frac{n}{k+1}$,因此$k+1$一定是$n$的因子,若此时还满足子树大小为它的倍数的点数够$k+1$个,则可行。

    #include<cstdio>
    const int N=1000010;
    int n,i,x,y,g[N],v[N<<1],nxt[N<<1],ed;
    int size[N];
    int cnt[N];
    inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    void dfs(int x,int y){
    	size[x]=1;
    	for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x),size[x]+=size[v[i]];
    	cnt[size[x]]++;
    }
    inline bool check(int x){
    	x++;
    	if(n%x)return 0;
    	int w=n/x,t=0;
    	for(int i=w;i<=n;i+=w)t+=cnt[i];
    	return t==x;
    }
    int main(){
    	scanf("%d",&n);
    	for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
    	dfs(1,0);
    	for(i=1;i<n;i++)if(check(i))printf("%d ",i);
    }
    

      

    K. Kitchen Knobs

    因为$7$的因子只有$1$和$7$,因此最大值要么有$1$种,要么有$7$种,$7$种的显然无论怎么操作都是最优的,可以直接删掉。

    问题转化为:给定$n$个数$a_1,a_2,...,a_n$,每次可以选择一个区间加上一个数,用最少的操作次数让所有数模$7$都为$0$。

    将$a$差分,区间加操作也差分,则问题转化为:每次可以选择两个数,一个加上$k$,另一个减去$k$,用最少的操作次数让所有数模$7$都为$0$。

    首先无视$0$,那么一定是先$1,6$配对、$2,5$配对、$3,4$配对,如此处理后最多还有$3$种数字$A,B,C$,问题转化为将这些数分成最多的组数,使得每组和都为$0$,记录$3$个数每个的个数然后DP即可。

    #include<cstdio>
    #include<string>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int N=505,inf=10000;
    int _,n,a[N],A,B,C,i,j,k,x,y,z,cnt[7],ans,m,e[N][4];short f[N][N][N],t;
    inline void up(short&a,short b){a>b?(a=b):0;}
    int ask(){
      static char s[20];
      scanf("%s",s);
      string best="";
      for(int i=0;i<7;i++)best.push_back(s[i]);
      int mask=1;
      int sum=0;
      for(int i=1;i<7;i++){
        string now="";
        for(int j=0;j<7;j++){
          now.push_back(s[(i+j)%7]);
        }
        if(now==best){
          mask|=1<<i;
          sum+=i;
        }else if(now>best){
          mask=1<<i;
          sum=i;
          best=now;
        }
      }
      if(mask!=(mask&(-mask)))return -1;
      return sum;
    }
    int main(){
      scanf("%d",&_);
      while(_--){
        int x=ask();
        if(x<0)continue;
        a[++n]=x;
      }
      if(!n)return puts("0"),0;
      for(i=n+1;i;i--)a[i]-=a[i-1];
      for(i=1;i<=n+1;i++)a[i]=((a[i]%7+7)%7);
      for(i=1;i<=n+1;i++)cnt[a[i]]++;
      while(cnt[1]&&cnt[6])cnt[1]--,cnt[6]--,ans++;
      A=cnt[1]?cnt[1]:cnt[6];
      x=cnt[1]?1:6;
      while(cnt[2]&&cnt[5])cnt[2]--,cnt[5]--,ans++;
      B=cnt[2]?cnt[2]:cnt[5];
      y=cnt[2]?2:5;
      while(cnt[3]&&cnt[4])cnt[3]--,cnt[4]--,ans++;
      C=cnt[3]?cnt[3]:cnt[4];
      z=cnt[3]?3:4;
      for(i=0;i<=7;i++)for(j=0;j<=7;j++)for(k=0;k<=7;k++)if(i+j+k&&(i*x+j*y+k*z)%7==0){
        e[m][0]=i;
        e[m][1]=j;
        e[m][2]=k;
        e[m++][3]=i+j+k-1;
      }
      for(i=0;i<=A;i++)for(j=0;j<=B;j++)for(k=0;k<=C;k++)if(i+j+k){
        t=inf;
        for(x=0;x<m;x++)if(i>=e[x][0]&&j>=e[x][1]&&k>=e[x][2])up(t,f[i-e[x][0]][j-e[x][1]][k-e[x][2]]+e[x][3]);
        f[i][j][k]=t;
      }
      printf("%d",ans+f[A][B][C]);
    }
    

      

    L. Lunar Landscape

    利用二维前缀和标记出所有被覆盖的位置即可。

    #include<cstdio>
    const int K=2005,N=4100;
    int n,x,y,d,i,j,k,a[N][N],b[N][N],f[N][N],ans;char op[9];
    int main(){
      scanf("%d",&n);
      while(n--){
        scanf("%s%d%d%d",op,&x,&y,&d);
        x+=K,y+=K;
        if(op[0]=='A'){
          x-=d/2,y-=d/2;
          a[x][y]++;
          a[x+d][y]--;
          a[x][y+d]--;
          a[x+d][y+d]++;
        }else{
          d/=2;
          b[x][y-d]++;
          b[x-d][y]--;
          b[x+d][y]--;
          b[x][y+d]++;
        }
      }
      for(i=1;i<N;i++)for(j=1;j<N;j++){
        a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
        if(a[i][j])f[i][j]|=15;
      }
      for(j=1;j<N;j++)for(i=1;i<N;i++){
        b[i][j]+=b[i-1][j-1]+b[i+1][j-1];
        if(j>=2)b[i][j]-=b[i][j-2];
        if(b[i][j]){
          f[i][j]|=12;
          f[i][j+1]|=9;
          f[i-1][j]|=6;
          f[i-1][j+1]|=3;
        }
      }
      for(i=1;i<N;i++)for(j=1;j<N;j++)for(k=0;k<4;k++)if(f[i][j]>>k&1)ans++;
      printf("%.2f",0.25*ans);
    }
    

      

  • 相关阅读:
    我国教育技术期刊主要栏目的内容分析
    是互动还是告状 “家校通”通往何处?(转)
    美国高中的班级管理制度
    什么是决策支持系统?
    2009 AECT International Convention
    AECT94定义和AECT2005定义
    感受美国小学生的幸福校园生活! (转)
    教育管理信息系统的研究
    教学评价的新发展
    抽象方法与虚方法(转)
  • 原文地址:https://www.cnblogs.com/clrs97/p/8041101.html
Copyright © 2011-2022 走看看