• Codeforces Round #551 (Div. 2) 题解


    CF1153A

    直接做啊,分类讨论即可

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    #define lowbit(x) (x)&(-x)
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,a,b) for (int i=a;i>=b;i--)
    #define maxd 1000000007
    typedef long long ll;
    const int N=100000;
    const double pi=acos(-1.0);
    
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    	return x*f;
    }
    
    int main()
    {
    	int n=read(),st=read(),ans=0,tim=maxd;
    	rep(i,1,n)
    	{
    		int s=read(),d=read();
    		if (s==st) {printf("%d",i);return 0;}
    		else if (s>st)
    		{
    			if (s<tim) {ans=i;tim=s;}
    		}
    		else
    		{
    			int tmp=(st-s-1)/d+1;
    			int now=(tmp*d+s);
    			if (now<tim) {ans=i;tim=now;}
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    

    CF1153B

    对于(h_{i,j}),我们有两个最小值的限制,那么我们强制(h_{i,j})为这两个限制最小值即可

    由于题目保证有解,故总存在对应的答案

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    #define lowbit(x) (x)&(-x)
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,a,b) for (int i=a;i>=b;i--)
    #define maxd 1000000007
    typedef long long ll;
    const int N=100000;
    const double pi=acos(-1.0);
    int n,m,h,blo[1010][1010],ans[1010][1010],x[1010],y[1010];
    
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    	return x*f;
    }
    
    int main()
    {
    	n=read();m=read();h=read();
    	rep(i,1,m) x[i]=read();
    	rep(i,1,n) y[i]=read();
    	rep(i,1,n)
    	{
    		rep(j,1,m)
    		{
    			blo[i][j]=read();
    		}
    	}
    	rep(i,1,n)
    	{
    		rep(j,1,m)
    		{
    			if (blo[i][j])
    			{
    				ans[i][j]=min(x[j],y[i]);
    			}
    		}
    	}
    	rep(i,1,n)
    	{
    		rep(j,1,m)
    		{
    			printf("%d ",ans[i][j]);
    		}
    		printf("
    ");
    	}
    	return 0;
    }
    

    CF1153C

    考虑如何构造一个合法的括号序列

    我们将(()看做(1),将())看做(-1),那么原括号序列合法的条件就是(forall iin [1..n],sum(1...i)>0)

    考虑这样的贪心:为了使前缀和尽可能的大,我们尽可能的将(()首先填完,之后剩下的位置再填()​)

    在首先判掉(()的个数超过一半了之后暴力扫描即可

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    #define lowbit(x) (x)&(-x)
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,a,b) for (int i=a;i>=b;i--)
    #define maxd 1000000007
    typedef long long ll;
    const int N=100000;
    const double pi=acos(-1.0);
    int n;
    char s[300500];
    
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    	return x*f;
    }
    
    int main()
    {
    	n=read();
    	scanf("%s",s+1);
    	if (n&1) {cout <<":(";return 0;}
    	int cnt=n/2;
    	rep(i,1,n) if (s[i]=='(') cnt--;
    	if (cnt<0) {cout << ":(";return 0;}
    	rep(i,1,n)
    	{
    		if (s[i]=='?')
    		{
    			if (cnt) {s[i]='(';cnt--;}
    			else {s[i]=')';}
    		}
    	}
    	//rep(i,1,n) putchar(s[i]);
    	int tmp=0;
    	rep(i,1,n-1)
    	{
    		if (s[i]=='(') tmp++;else tmp--;
    		if (tmp<=0) {cout << ":(";return 0;}
    	}
    	rep(i,1,n) putchar(s[i]);
    	return 0;
    }
    

    CF1153D

    (mdzz),在这题上卡住了

    注意到使得“根节点的值最大”的条件对任意子树都是成立的

    (dp[u])为在(u)点上的值是所有叶子上的值的第(k)大,那么最后的答案就是(cnt-dp[1]+1)

    那么对于(min)操作和(max​)操作进行分类讨论

    自己手玩一下便可以知道,(min)操作等价于(dp[u]=sum dp[v]),而(max)等价于(dp[u]=min(dp[v]))(v)(u)的儿子)

    直接(dfs)即可

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    #define lowbit(x) (x)&(-x)
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,a,b) for (int i=a;i>=b;i--)
    #define maxd 1000000007
    typedef long long ll;
    const int N=100000;
    const double pi=acos(-1.0);
    
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    	return x*f;
    }
    int n,all=0,ans,head[600600],w[600600],dp[600600],cnt=0;
    
    struct node {
    	int nxt,to;
    }sq[600500];
    
    void add(int u,int v)
    {
        all++;sq[all].nxt=head[u];sq[all].to=v;head[u]=all;
    }
    
    void dfs(int u,int fu)
    {
        if(!head[u]) 
    	{
    		cnt++;dp[u]=1; 
    		return;
    	}
        if(w[u]==1) dp[u]=maxd;
    	int i;
        for(i=head[u];i;i=sq[i].nxt)
        {
            int v=sq[i].to;
            dfs(v,u);
            if(w[u]==1) dp[u]=min(dp[u],dp[v]);
            else dp[u]+=dp[v];
        }
    }
    
    int main()
    {
        n=read();
        rep(i,1,n) w[i]=read();
        rep(i,2,n)
        {
            int fu=read();add(fu,i);
        }
        dfs(1,0);
        printf("%d
    ",cnt+1-dp[1]);
        return 0;
    }
    

    CF1153E

    CF的交互(尤其是(div 2))基本上就是用来理性愉悦的

    假设你从这条蛇的头部走到尾部,每次询问一个方格,你会发现只有在头部和尾部你会询问到奇数的答案,其他位置都是偶数,这十分好理解:对于除去头部和尾部的其他格子而言,为了保证蛇的连通性,必然是一次“进入”询问区间对应着恰好一次“走出”询问区间,即对询问答案个贡献一定是成对出现的

    但是对于头部和尾部却不是这样,由于他会有一次“进入”或“走出”操作时突然出现的,所以它对答案的贡献一定是奇数

    为了减少询问同时方便定位(就是从询问次数的大小发现的规律),我们可以暴力询问每一行和每一列共(2n)次询问,记录下来得到奇数答案的对应的行和列,然后分类讨论

    1)假设得到了4个值,我们随意询问一个合法的格子,如果答案是奇数那么它就是一个头,否则将它对应的行和列拆开得到新的两个格子即为答案

    2)假设得到了2个值,说明两个格子同行或同列,我们对于剩下的(19)次询问考虑二分,如每次询问(1-mid)的所有行(或列),如果答案是奇数的话那么答案就在此区间,否则就在另一个区间

    很明显答案只有以上两种情况

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    #define lowbit(x) (x)&(-x)
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,a,b) for (int i=a;i>=b;i--)
    #define maxd 1000000007
    typedef long long ll;
    const int N=100000;
    const double pi=acos(-1.0);
    int n;
    
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    	return x*f;
    }
    
    int main()
    {
    	n=read();
    	int x1=0,y1=0,x2=0,y2=0,got=0;
    	rep(i,1,n)
    	{
    		printf("? %d %d %d %d
    ",i,1,i,n);fflush(stdout);
    		int cnt=read();
    		if (cnt&1) 
    		{
    			if (x1) x2=i;else x1=i;
    			got++;
    		}
    	}
    	rep(i,1,n)
    	{
    		printf("? %d %d %d %d
    ",1,i,n,i);fflush(stdout);
    		int cnt=read();
    		if (cnt&1)
    		{
    			if (y1) y2=i;else y1=i;
    			got++;
    		}
    	}
    	if (got==4)
    	{
    		printf("? %d %d %d %d
    ",x1,y1,x1,y1);fflush(stdout);
    		int cnt=read();
    		if ((cnt&1)==0) swap(x1,x2);
    		printf("! %d %d %d %d
    ",x1,y1,x2,y2);fflush(stdout);
    	}
    	else
    	{
    		if (x1)
    		{
    			int l=1,r=n,ansy;
    			while (l<=r)
    			{
    				int mid=(l+r)>>1;
    				printf("? %d %d %d %d
    ",x1,l,x1,mid);fflush(stdout);
    				int cnt=read();
    				if (cnt&1) {ansy=mid;r=mid-1;}
    				else {l=mid+1;}
    			}
    			printf("! %d %d %d %d
    ",x1,ansy,x2,ansy);fflush(stdout);
    		}
    		else
    		{
    			int l=1,r=n,ansx;
    			while (l<=r)
    			{
    				int mid=(l+r)>>1;
    				printf("? %d %d %d %d
    ",l,y1,mid,y1);fflush(stdout);
    				int cnt=read();
    				if (cnt&1) {ansx=mid;r=mid-1;}
    				else l=mid+1;
    			}
    			printf("! %d %d %d %d
    ",ansx,y1,ansx,y2);fflush(stdout);
    		}
    	}
    	return 0;
    }
    

    CF1153F

    答案可以看做(每一段的期望长度*每一次的期望段数)

    前者的答案是(frac{l}{2n+1}),关键是如何计算后者

    (dp[i][j])为当前有(i)个节点,其中有(j)个节点没有右端点与其匹配的方案数

    在枚举是按照当前的点是否配对即可,即对于(dp[i][j]),有

    [dp[i+1][j+1]+=dp[i][j]\ dp[i+1][j-1]+=dp[i][j]*j ]

    统计答案时,枚举左半边有(i)个点且有(j)(jleq k))个点未匹配,则(ans=sum dp[i][j]*dp[n*2-i][j]*j!)

    最后两者相乘即可

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    #define lowbit(x) (x)&(-x)
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,a,b) for (int i=a;i>=b;i--)
    #define maxd 998244353
    typedef long long ll;
    const int N=100000;
    const double pi=acos(-1.0);
    int n,k,l;
    ll dp[4020][4020],fac[4040];
    
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    	while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    	return x*f;
    }
    
    ll qpow(ll x,int y)
    {
    	ll ans=1;
    	while (y)
    	{
    		if (y&1) ans=(ans*x)%maxd;
    		x=(x*x)%maxd;
    		y>>=1;
    	}
    	return ans;
    }
    
    ll inv(ll x) {return qpow(x,maxd-2);}
    
    int main()
    {
    	n=read();k=read();l=read();
    	dp[0][0]=1;
    	rep(i,0,n*2)
    	{
    		rep(j,0,min(i,n))
    		{
    			dp[i+1][j+1]=(dp[i+1][j+1]+dp[i][j])%maxd;
    			dp[i+1][j-1]=(dp[i+1][j-1]+dp[i][j]*j)%maxd;
    		}
    	}
    	fac[0]=1;
    	rep(i,1,4000) fac[i]=(fac[i-1]*i)%maxd;
    	ll ans=0;
    	rep(i,1,n*2)
    	{
    		rep(j,k,min(i,n))
    		{
    			ans=(ans+((dp[i][j]*dp[n*2-i][j])%maxd*fac[j])%maxd)%maxd;
    		}
    	}
    	ll len=l*inv(n*2+1)%maxd;
    	ans=ans*inv(dp[n*2][0])%maxd;
    	ans=ans*len%maxd;
    	printf("%lld",ans);
    	return 0;
    }
    

    code

  • 相关阅读:
    使用PowerShell脚本来轮训Exchange数据库的状态
    使用NUnit在.Net编程中进行单元测试【转载】
    利用NUnit对类、方法进行原子级测试
    单元测试的重要性
    不用临时变量,只用11个字符交换两个变量的值——窥视C#编译原理的冰山一角
    博客园
    c++的float(NaN)
    mysql之innodb的锁分类
    配置alchemc时cygwin下面,特别要注意路径
    关于异步调用Discuz!NT接口
  • 原文地址:https://www.cnblogs.com/encodetalker/p/10708236.html
Copyright © 2020-2023  润新知