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就掉的很惨,怕不会重新开个号
    另外,现在看英文题解能力还是不行,每句话能凑合看懂,但是连起来就不知道在说啥了

  • 相关阅读:
    关于上传的种种(一)
    由SharePoint:ChangeContentType想到的
    关于上传的种种(二)
    关于上传的种种(三)
    SharePoint 2013 Suite Bar
    SharePoint 2013 商城
    自定义列表默认的视图文件
    InfoPath表单与SPD无代码工作流(一)
    列表的展示分页
    无处不在的SharePoint按钮(二)
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/12221552.html
Copyright © 2011-2022 走看看