zoukankan      html  css  js  c++  java
  • Codeforces round 1086

    Div1 528

    • 我菜哭了.jpg
    • 这个C的出题人能不能停止出题啊QaQ

    A

    • 这不是裸的斯坦纳树嘛!

    然后我就写上了.jpg

    然后我没调出来...

    然后我发现...这不是傻逼题吗...

    直接按照$x$排序,然后做一条恰好够高的线

    分别连向两边...

    完事了.jpg

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <queue>
    using namespace std;
    struct node{int x,y;}s[10];
    bool cmp(const node &a,const node &b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    int main()
    {
    	for(int i=1;i<=3;i++)scanf("%d%d",&s[i].x,&s[i].y);
    	sort(s+1,s+4,cmp);
    	int l=min(s[1].y,min(s[2].y,s[3].y)),r=max(s[1].y,max(s[2].y,s[3].y));
    	printf("%d
    ",(s[3].x-s[1].x)+r-l+1);
    	for(int i=l;i<=r;i++)printf("%d %d
    ",s[2].x,i);
    	for(int i=s[1].x;i<s[2].x;i++)printf("%d %d
    ",i,s[1].y);
    	for(int i=s[2].x+1;i<=s[3].x;i++)printf("%d %d
    ",i,s[3].y);
    }
    

    B

    一个非常显然的贪心,就是把权值全都放在叶子上...

    然后就完事了.jpg

    #include<set>
    #include<map>
    #include<queue>
    #include<cmath>
    #include<stack>
    #include<cstdio>
    #include<bitset>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define N 100005
    int d[N],n,x,y;
    int ans;
    double m;
    int main()
    {
    	scanf("%d%lf",&n,&m);
    	for(int i=1;i<n;i++)scanf("%d%d",&x,&y),d[x]++,d[y]++;
    	if(n==2)return printf("%.6f
    ",m),0;
    	for(int i=1;i<=n;i++)ans+=(d[i]==1);
    	return printf("%.7f
    ",m/ans*(double)2),0;
    }
    

    C

    没有题解,题目非常傻逼

    直接分类讨论即可.jpg

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <queue>
    using namespace std;
    #define N 1000005
    char a[N],b[N],s[N];
    int k,T,tmp[27],vis[27],p,n,tt[27],vv[27];
    bool check(int x,int cas)
    {
    	memcpy(tt,tmp,sizeof(tt));
    	memcpy(vv,vis,sizeof(vv));
    	if(cas==1)
    	{
    		for(int i=x;i<=n;i++)
    		{
    			if(tt[s[i]-'a']!=-1)
    			{
    				if(tt[s[i]-'a']>a[i])return 1;
    				if(tt[s[i]-'a']<a[i])return 0;
    				continue;
    			}
    			for(int j=a[i]+1;j<=k+'a'-1;j++)if(!vv[j-'a'])return 1;
    			if(!vv[a[i]-'a'])vv[a[i]-'a']=1,tt[s[i]-'a']=a[i];
    			else return 0;
    		}
    		return 1;
    	}else
    	{
    		for(int i=x;i<=n;i++)
    		{
    			if(tt[s[i]-'a']!=-1)
    			{
    				if(tt[s[i]-'a']>b[i])return 0;
    				if(tt[s[i]-'a']<b[i])return 1;
    				continue;
    			}
    			for(int j='a';j<b[i];j++)if(!vv[j-'a'])return 1;
    			if(!vv[b[i]-'a'])vv[b[i]-'a']=1,tt[s[i]-'a']=b[i];
    			else return 0;
    		}
    		return 1;
    	}
    }
    void solve()
    {
    	scanf("%d%s%s%s",&k,s+1,a+1,b+1);
    	n=strlen(s+1);
    	memset(tmp,-1,sizeof(tmp));p=n+1;
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<=n;i++)
    		if(a[i]==b[i])
    		{
    			if(tmp[s[i]-'a']==a[i])continue;
    			if(tmp[s[i]-'a']==-1&&!vis[a[i]-'a'])tmp[s[i]-'a']=a[i],vis[a[i]-'a']=1;
    			else{puts("NO");return ;}
    		}else{p=i;break;}
    	int flag=0;
    	for(int i=p;i<=n;i++)
    	{
    		if(!flag&&a[i]>b[i]){puts("NO");return ;}
    		if(tmp[s[i]-'a']!=-1)
    		{
    			if((((flag&2)==0)&&tmp[s[i]-'a']<a[i])||(((flag&4)==0)&&tmp[s[i]-'a']>b[i])){puts("NO");return ;}
    			if((flag&2)==0&&tmp[s[i]-'a']>a[i])flag|=2;
    			if((flag&4)==0&&tmp[s[i]-'a']<b[i])flag|=4;
    		}else if((flag&6)==0)
    		{
    			bool used=0;
    			for(int j=a[i]+1;j<b[i];j++)
    				if(!vis[j-'a'])
    				{
    					tmp[s[i]-'a']=j;
    					vis[j-'a']=1;
    					flag|=6;
    					used=1;
    					break;
    				}
    			if(!used)
    			{
    				if(!used&&!vis[b[i]-'a'])
    				{
    					vis[b[i]-'a']=1,tmp[s[i]-'a']=b[i];
    					if(!check(i+1,2))vis[b[i]-'a']=0,tmp[s[i]-'a']=-1;
    					else flag|=2,used=1;
    				}
    				if(!used&&!vis[a[i]-'a'])
    				{
    					vis[a[i]-'a']=1,tmp[s[i]-'a']=a[i];
    					if(check(i+1,1))flag|=4,used=1;
    				}
    				if(!used){puts("NO");return ;}
    			}
    		}else if((flag&2)==0)
    		{
    			bool used=0;
    			for(int j=a[i]+1;j<=k+'a'-1;j++)
    				if(!vis[j-'a'])
    				{
    					tmp[s[i]-'a']=j;
    					vis[j-'a']=1;
    					flag|=2;
    					used=1;
    					break;
    				}
    			if(!used)
    			{
    				if(!vis[a[i]-'a'])vis[a[i]-'a']=1,tmp[s[i]-'a']=a[i];
    				else{puts("NO");return ;}
    			}
    		}else if((flag&4)==0)
    		{
    			bool used=0;
    			for(int j='a';j<b[i];j++)
    				if(!vis[j-'a'])
    				{
    					tmp[s[i]-'a']=j;
    					vis[j-'a']=1;
    					flag|=4;
    					used=1;
    					break;
    				}
    			if(!used)
    			{
    				if(!vis[b[i]-'a'])vis[b[i]-'a']=1,tmp[s[i]-'a']=b[i];
    				else{puts("NO");return ;}
    			}
    		}
    		flag|=1;
    		if(flag==7)break;
    	}
    	puts("YES");
    	int now=0;
    	while(vis[now])now++;
    	for(int i=0;i<k;i++)
    		if(tmp[i]==-1){tmp[i]='a'+now;vis[now]=1;while(vis[now])now++;}
    	for(int i=0;i<k;i++)printf("%c",tmp[i]);puts("");
    }
    int main()
    {
    	scanf("%d",&T);
    	while(T--)solve();
    }
    

    ...

    然后发现...可以搜索...

    而且代码巨简单.jpg

    D

    分析一波性质发现:

    在每个位置的两侧同时出现一个能输给他的,他就一定有可能能赢...

    或者,在他的某一侧同时没有输给他的和赢他的,他也一定有可能能赢...

    然后set+树状数组就行

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    #include <bitset>
    #include <set>
    using namespace std;
    #define N 200005
    struct BIT
    {
    	int s[N];
    	void fix(int x,int op){for(;x<N;x+=x&-x)s[x]+=op;}
    	int find(int x){int ret=0;for(;x;x-=x&-x)ret+=s[x];return ret;}
    	int get(int l,int r){return find(r)-find(l-1);}
    }b[3];
    set<int>s[3];
    int a[128],n,Q;
    char str[N],opt[3];
    int calc()
    {
    	int ans=0;
    	for(int i=0;i<3;i++)
    	{
    		if(s[(i+1)%3].empty()){ans+=s[i].size();continue;}
    		if(s[(i+2)%3].empty())continue;
    		int L=*s[(i+2)%3].begin(),R=*(--s[(i+2)%3].end());
    		ans+=b[i].get(L,R);
    		int X=*s[(i+1)%3].begin(),Y=*(--s[(i+1)%3].end());
    		ans+=b[i].find(min(L,X)-1)+b[i].get(max(R,Y)+1,n);
    	}
    	return ans;
    }
    int main()
    {
    	a['R']=0;a['P']=1;a['S']=2;
    	scanf("%d%d%s",&n,&Q,str+1);
    	for(int i=1;i<=n;i++)s[a[str[i]]].insert(i),b[a[str[i]]].fix(i,1);
    	printf("%d
    ",calc());
    	while(Q--)
    	{
    		int x;scanf("%d%s",&x,opt);
    		s[a[str[x]]].erase(x);b[a[str[x]]].fix(x,-1);
    		str[x]=opt[0];
    		s[a[str[x]]].insert(x),b[a[str[x]]].fix(x,1);
    		printf("%d
    ",calc());
    	}
    }
    

    E

    非常有意思的树状数组优化DP,非常厉害的数数题...

    按照正常思路,求一个当前一定比它小的个数,然后递归下去可能比它小的个数...

    然后求出一个$i$个数组成一个排列,给你$i$个数有$j$个在这$i$个数里出现过,然后错排的方案数...

    然后把这个东西求出来之后,用树状数组维护这一行和上一行的状态,就可以知道有多少个数在$i$个里出现过了...以及当前位置有多少个比它小的数的个数...

    然后就完事了...

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    #include <bitset>
    using namespace std;
    #define N 2005
    #define ll long long
    #define mod 998244353
    int a[N][N],f[N][N],n,fac[N],ans,g[N],c[N],s[N],pf[N],vis1[N],vis2[N];
    void fix(int *a,int x,int op){for(;x<=n;x+=x&-x)a[x]+=op;}
    int find(int *a,int x){int ret=0;for(;x;x-=x&-x)ret+=a[x];return ret;}
    void init(){memset(c,0,sizeof(c));memset(s,0,sizeof(s));}
    int main()
    {
    	scanf("%d",&n);fac[0]=1;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			scanf("%d",&a[i][j]);g[1]=0,g[2]=1;
    	for(int i=1;i<=n;i++)fac[i]=(ll)fac[i-1]*i%mod;
    	for(int i=3;i<=n;i++)g[i]=(ll)(g[i-1]+g[i-2])*(i-1)%mod;
    	for(int i=1;i<=n;i++)
    	{
    		f[i][0]=fac[i];
    		for(int j=1;j<i;j++)f[i][j]=((ll)(i-j)*f[i-1][j]+(ll)j*f[i-1][j-1])%mod;
    		f[i][i]=g[i];
    	}pf[0]=1;
    	for(int i=1;i<=n;i++)pf[i]=(ll)pf[i-1]*g[n]%mod;
    	init();
    	for(int i=n;i;i--)
    	{
    		fix(c,a[1][i],1);
    		ans=(ans+(ll)find(c,a[1][i]-1)*fac[n-i]%mod*pf[n-1])%mod;
    	}
    	for(int i=2;i<=n;i++)
    	{
    		init();memset(vis1,0,sizeof(vis1));memset(vis2,0,sizeof(vis2));
    		for(int j=n;j;j--)
    		{
    			vis2[a[i][j]]=1;
    			if(!vis1[a[i][j]])fix(c,a[i][j],1);
    			else fix(s,a[i][j],1);
    			int cnt=find(s,n);
    			ans=(ans+(ll)find(c,a[i][j]-1)*f[n-j][cnt]%mod*pf[n-i])%mod;
    			if(cnt)ans=(ans+(ll)find(s,a[i][j]-1)*f[n-j][cnt-1]%mod*pf[n-i])%mod;
    			if(a[i][j]>a[i-1][j]&&vis2[a[i-1][j]])
    				ans=(ans-(ll)f[n-j][cnt]*pf[n-i])%mod;
    			if(!vis2[a[i-1][j]])vis1[a[i-1][j]]=1;
    			else
    			{
    				vis1[a[i-1][j]]=1;
    				fix(c,a[i-1][j],-1);
    				fix(s,a[i-1][j],1);
    			}
    		}
    	}
    	printf("%d
    ",(ans+mod)%mod);
    }
    
  • 相关阅读:
    DbHelperSQL
    弹出插件
    C#汉字转换拼音技术详解(高性能)
    js转移符
    服务器端世界时间(UTC)转换客户端时区时间
    asp.net分页存储过程
    开放式并发的解决办法
    关于批量数据更新的问题(C#高性能)
    Url相对路径和绝对路径的问题总结
    英文字体运用
  • 原文地址:https://www.cnblogs.com/Winniechen/p/10353656.html
Copyright © 2011-2022 走看看