zoukankan      html  css  js  c++  java
  • Codeforces Round #614 (Div. 2)

    A. ConneR and the A.R.C. Markland-N

    题解

    拍完序之后往两边搜就行,不知道为啥,最近代码写的奇丑无比

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    #define mem(a,b) memset(a,b,sizeof(a))
    typedef long long LL;
    typedef pair<int,int> PII;
    #define X first
    #define Y second
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    const int maxn=1010;
    int T,n,s,k,a[maxn];
    int main()
    {
    	T=read();
    	while(T--)
    	{
    		bool ok=0;
    		n=read();s=read();k=read();
    		for(int i=1;i<=k;i++)
    		{
    			a[i]=read();
    			if(a[i]==s)ok=1;
    		}
    		if(!ok){printf("0
    ");continue;}
    		sort(a+1,a+k+1);
    		int pos=0,ans=2147483647,tmp;
    		for(int i=1;i<=k;i++)if(a[i]==s)pos=i;
    		tmp=pos;
    		while(tmp && s-a[tmp]==pos-tmp)tmp--;
    		if(a[tmp+1]!=1)ans=pos-tmp;
    		tmp=pos;
    		while(tmp<=k && a[tmp]-s==tmp-pos)tmp++;
    		if(a[tmp-1]!=n)ans=min(ans,tmp-pos);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    B. JOE is on TV!

    题解

    (f[i]) 表示(i) 时候的最优解,转移很显然:$ f[i]=max (f[j]+1-j/i)$ ,然后再稍微动动脑子就会发现(j=i-1) 的时候最优,然后就递推(O(n)) 就好了

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    #define mem(a,b) memset(a,b,sizeof(a))
    typedef long long LL;
    typedef pair<int,int> PII;
    #define X first
    #define Y second
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    double f[100010]; 
    int n;
    int main()
    {
    	n=read();
    	f[1]=1.0;
    	for(int i=2;i<=n;i++)f[i]=f[i-1]+1.0-(double)(i-1)/(double)i;
    	printf("%.10lf
    ",f[n]);
    	return 0;
    }
    

    C. NEKO's Maze Game

    题解

    之前很久以前做过一道类似的题,然后就往那个方向去想,结果越想越离谱,冷静一下发现这是DIV2T3
    对于每一个修改成不能走的点,判一下他的(上或下)的左中右是否有块,表示堵住路的数量,对于修改成能走的,继续模仿上一步,有块的减去,表示这块路能走了。
    这道题是(n=2) 的情况,我想了想,如果是一般情况的话就得用可持久化并查集维护上下的连通性了。

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    #define mem(a,b) memset(a,b,sizeof(a))
    typedef long long LL;
    typedef pair<int,int> PII;
    #define X first
    #define Y second
    inline int read()
    {
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    const int maxn=100010;
    int n,Q,x,y,blo[3][maxn],blocked;
    int main()
    {
    	n=read();Q=read();
    	while(Q--)
    	{
    		x=read();y=read();
    		blo[x][y]^=1;
    		if(blo[x][y])
    		{
    			for(int i=-1;i<=1;i++)
    				if(y+i>=1 && y+i<=n && blo[3-x][y+i])blocked++;
    		}
    		else
    		{
    			for(int i=-1;i<=1;i++)
    				if(y+i>=1 && y+i<=n && blo[3-x][y+i])blocked--;
    		}	
    		if(!blocked)printf("Yes
    ");
    		else printf("No
    ");
    	}
    	return 0;
    }
    

    题解

    发现系数最少就是2,这种指数型增长谁受得了,撑不到几十次就炸了。所以能走到的点很少,对于剩下的点暴力走一走就好了。
    我的走法是从起点到任意一个点,然后分别往左走往右走统计最长路。
    第一次还wa了,发现是阈值定小了。

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<queue>
    using namespace std;
    #define mem(a,b) memset(a,b,sizeof(a))
    typedef long long LL;
    typedef pair<int,int> PII;
    #define X first
    #define Y second
    inline LL read()
    {
    	LL x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    const int maxn=10000;
    LL X0,Y0,ax,ay,bx,by,xs,ys,t,x[maxn],y[maxn],xx[maxn],yy[maxn],End,len,ans,tans;
    LL labs(LL a){return a<0 ? -a : a;} 
    LL dis(LL a,LL b,LL c,LL d){return labs(c-a)+labs(d-b);}
    int main()
    {
    	X0=read();Y0=read();ax=read();ay=read();bx=read();by=read();
    	xs=read();ys=read();t=read();
    	x[End]=X0,y[End++]=Y0;
    	while(dis(x[0],y[0],ax*x[End-1]+bx,ay*y[End-1]+by)<=3ll*(LL)1e16)x[End]=ax*x[End-1]+bx,y[End]=ay*y[End-1]+by,End++;
    	for(int i=0;i<End;i++)if(dis(xs,ys,x[i],y[i])<=t)xx[len]=x[i],yy[len++]=y[i];
    	for(int i=0;i<len;i++)
    	{
    		LL step=t-dis(xx[i],yy[i],xs,ys),tans=1;
    		int pos=i;
    		while(pos+1<len && step-dis(xx[pos],yy[pos],xx[pos+1],yy[pos+1])>=0)tans++,step-=dis(xx[pos],yy[pos],xx[pos+1],yy[pos+1]),pos++;
    		ans=max(ans,tans);
    		step=t-dis(xx[i],yy[i],xs,ys),tans=1;pos=i;
    		while(pos-1>=0 && step-dis(xx[pos],yy[pos],xx[pos-1],yy[pos-1])>=0)tans++,step-=dis(xx[pos],yy[pos],xx[pos-1],yy[pos-1]),pos--;
    		ans=max(ans,tans);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    E. Xenon's Attack on the Gangs

    题解

    好吧,看完题解之后想了半天才懂
    首先,对公式有一个转化:(S=sum_{1leq u,vleq n} mex(u,v)=sum_{1leq x leq n} (sum_{mex(u,v)geq x}))
    这个转化我就根本想不到,希望可以以后用作套路?
    转化成通俗的语言就是计算大于等于(x) 的对数,(其中(1leq x leq n)
    现在考虑怎么计算(mex(u,v)geq x) 的对数。
    根据(mex) 函数的性质,(x) 发挥作用的时候的前提是(0,1,...,x-1) 必须在之前的树链中出现, 所以(x) 这条边权必须插在路径由(0,1,...,x-1)组成树链的后面
    设树链两端分别为(u,fa[v]),(v)是我们要接在(fa[v]) 后面的,那么这个玩意产生的贡献是:(size[u]*size[v]) 具体对应哪个根已经乱套了,反正就是那两边的子树相乘,这个玩意就是(mex(u,v)geq x) 的对数。
    然后依据这个性质,设(dp[u][v]) 表示把(0,1,...,l-1)怼在(u,v) 两端的答案,转移的话,就是往两端继续接新的节点,复杂度(O(n^2))
    代码懒得自己写了,直接蒯的别人的
    好难啊,好难啊

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll maxn=3e3+10;
    ll head[maxn];
    ll sz[maxn][maxn];
    ll f[maxn][maxn];
    ll dp[maxn][maxn];
    struct Edge{
        ll v,next;
    }e[maxn<<1];
    ll cnt=0;
    void add(ll u,ll v){
        e[cnt].v=v;
        e[cnt].next=head[u];
        head[u]=cnt++;
    }
    void dfs(ll u,ll fa,ll root){
        sz[root][u]=1;
        f[root][u]=fa;
        for(ll i=head[u];~i;i=e[i].next){
            ll v=e[i].v;
            if(v==fa)continue;
            dfs(v,u,root);
            sz[root][u]+=sz[root][v];
        }
    }
    ll solve(ll i,ll j){
        if(dp[i][j]!=-1)return dp[i][j];
        if(i==j)return dp[i][j]=0;
        return dp[i][j]=sz[i][j]*sz[j][i]+max(solve(f[i][j],i),solve(f[j][i],j));
    }
    int main(){
        memset(head,-1,sizeof(head));
        memset(dp,-1,sizeof(dp));
        ll n;
        scanf("%lld",&n);
        for(ll i=1;i<n;i++){
            ll u,v;
            scanf("%lld%lld",&u,&v);
            add(u,v);
            add(v,u);
        }
        for(ll i=1;i<=n;i++){
            dfs(i,-1,i);
        }
        ll ans=0;
        for(ll i=1;i<=n;i++){
            for(ll j=1;j<=n;j++){
                ans=max(ans,solve(i,j));
            }
        }
        cout<<ans<<endl;
    }
    

    F. Chaotic V.

    题解

    真是太感谢钟梓皓学长耐心的把我这道题教会了!!
    首先一个普适性的问题,一棵树上有若干个关键点,选取一个点使得所有关键到他的距离和最小。
    这个怎么做呢?先设点在根,然后开始模拟这个点的移动。假设这个点要往以根为(u) 的子树上移动,对答案造成的影响是(n-2*size[u]) ,所以只需要找到最大的(size[u]) ,并判断是否(n-2*size[u]) 小于0即可,这么着每一次(maxsize) 最少减1,复杂度是(O(n))
    然后对每一个阶乘预处理出所有的因子就好了

    #include <bits/stdc++.h>
     
    #define f first
    #define s second
    #define ll long long
    #define ull unsigned long long
    #define mp make_pair
    #define pb push_back
    #define vi vector <int>
    #define ld long double
    #define pii pair<int, int>
    #define y1 sda
     
    using namespace std;    
    const int N = 5000 + 12, mod = int(1e9)  + 7; 
     
    int n,lp[N],cnt[N],c1[N], pref[N], c2[N], d[N], pr[N], pn,num[N], dist[N][N];
    ll ans;
     
    int sz;
    vector <int> g[N], all;
     
    int main () {
    	scanf("%d", &n);
     
    	for(int i = 1,x; i <= n; i++){
    		scanf("%d", &x);
    		sz = max(sz, x);
    		if(x == 0) x++;
    		cnt[x]++;
    	}
     
    	//sz = 5000;
     
    	for(int i = 2; i <= sz; i++) if(!lp[i]){
    		pr[++pn] = i;
    		num[i] = pn;
    		for(int j = i; j <= sz; j += i) lp[j] = i;
    	}
    	for(int i = 2,x,p; i <= sz; i++){
    	    x = i;
    	    d[i] += d[i - 1];
    	    while(x > 1){
    	    	p = lp[x];
    	    	while(x % p == 0){
    	    		x /= p;
    	    		d[i]++;
    	    	}
    	    }
    	}
    	for(int i = 1,x,p; i <= sz; i++){
    		x = i;
    		while(x > 1){
    			p = lp[x];
    			while(x % p == 0){
    				x /= p;
    				c1[num[p]]++;
    			}
    		}
    		for(int j = 1; j <= pn; j++){
    			if(c1[j] > 0){
    				int x = c1[j];
    				while(x --> 0){
    					g[i].pb(j);
    				}
    			}
    		}
    		all.pb(i);
    	}
     
    	ans = 0;
     
    	for(int i : all){
    		ans += 1ll * cnt[i] * d[i];
    	}
     
    	while(true){
    		int res = 0, mx = 0, id = 0;
    		for(int i : all){
    			res += cnt[i];
    			if(g[i].size() > 0){
    				c2[g[i].back()] += cnt[i];	
    			}
    		}
    		for(int j = 1; j <= pn; j++){
    			if(c2[j] > mx){
    				mx = c2[j];
    				id = j;
    			}
    			c2[j] = 0;
    		}
    		if(2 * mx <= n){
    			break;
    		}
    		else{
    			ans += n - 2 * mx;
    			vector <int> cur;
    			for(int i : all){
    				if(g[i].size() > 0 && g[i].back() == id){
    					g[i].pop_back();
    					cur.pb(i);
    				}
    			} 
    			all = cur;
    		}
    	}
     
    	printf("%lld", ans);
     
     
     
    return 0;
    }
    

    废话

    这两次cf太浪了,开局rating就掉的很惨,怕不会重新开个号
    另外,现在看英文题解能力还是不行,每句话能凑合看懂,但是连起来就不知道在说啥了

  • 相关阅读:
    组装query,query汇总,query字段
    POJ 1276, Cash Machine
    POJ 1129, Channel Allocation
    POJ 2531, Network Saboteur
    POJ 1837, Balance
    POJ 3278, Catch That Cow
    POJ 2676, Sudoku
    POJ 3126, Prime Path
    POJ 3414, Pots
    POJ 1426, Find The Multiple
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/12221552.html
Copyright © 2011-2022 走看看