• 某古 11 月月赛 I 游记


    某古 11 月月赛 I 游记

    难度好评,没有像我上次打的那场比赛那么水了,不过自己的分数还是好低,只会前三题。。。

    希望你古月赛的题目一直都能像这场这么有意思。

    A 「MCOI-03」正方

    题目分析

    三角形面积公式 (S=frac{1}{2}ah) ,由于 (a) 相等,所以题目给出的其实就是 (h) 之比。

    题目中给出了 (a,b,c,d) ,不妨令 (ale ble cle d) ,由于题目给出的是正方形,所以必须要满足 (a+d=b+c) ,否则不是正方形,答案就是 (0) ,如果满足 (a+d=b+c) ,不妨令正方形的左下角为 ((0,0)) ,正方形边长为 (a+d) ,那么这个点的选择方法就只有 ((a,b),(a,c),(b,a),(c,a),(d,b),(d,c),(b,d),(c,d)) 八种,排序后去重就行了。

    参考代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ch() getchar()
    #define pc(x) putchar(x)
    template<typename T>inline void read(T&x){
    	int f;char c;
    	for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
    	for(x=0;c<='9'&&c>='0';c=ch())x=x*10+(c&15);x*=f;
    }
    template<typename T>inline void write(T x){
    	static char q[64];int cnt=0;
    	if(!x)pc('0');if(x<0)pc('-'),x=-x;
    	while(x)q[cnt++]=x%10+'0',x/=10;
    	while(cnt--)pc(q[cnt]);
    }
    long long A[4];
    pair<long long,long long>s[8];
    int main(){
    	int q;read(q);
    	while(q--){
    		for(int i=0;i<4;++i)read(A[i]);sort(A,A+4);
    		if(A[0]+A[3]!=A[1]+A[2])puts("0");
    		else{
    			int cn=0;
    			for(int i=0;i<=3;i+=3){
    				for(int j=1;j<=2;j+=1){
    					s[cn++]=pair<long long,long long>(A[i],A[j]);
    					s[cn++]=pair<long long,long long>(A[j],A[i]);
    				}
    			}
    			sort(s,s+cn);cn=unique(s,s+cn)-s;write(cn),pc('
    ');
    		}
    	} 
    	return 0;
    }
    
    

    B 「MCOI-03」村国

    题目分析

    一开始看到这题真的没有头绪,但是仔细思考后发现题面就是唬人的,感觉这样的题目还是挺有意思的。

    假如当前好感值最高的点是 (x) ,那么会先选择一直去 (x) 直到 (x) 旁边出现了一个点的好感值和 (x) 相等并且编号尽可能小,不妨设这个点为 (y) ,那么就会一直先去 (x,y) 中编号小的,然后去 (x,y) 中编号大的一直循环,所以此时只需要判断 (m) 的奇偶性就行了。

    需要注意的一点就是如果 (x) 不存在相邻的点答案就是 (x)

    参考代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ch() getchar()
    #define pc(x) putchar(x)
    template<typename T>inline void read(T&x){
    	int f;char c;
    	for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
    	for(x=0;c<='9'&&c>='0';c=ch())x=x*10+(c&15);x*=f;
    }
    template<typename T>inline void write(T x){
    	static char q[64];int cnt=0;
    	if(!x)pc('0');if(x<0)pc('-'),x=-x;
    	while(x)q[cnt++]=x%10+'0',x/=10;
    	while(cnt--)pc(q[cnt]);
    }
    const int maxn=2000006;
    int a[maxn];
    int main(){
    	int T;read(T);
    	while(T--){
    		int n;long long m;int po=0;read(n),read(m);
    		for(int i=1;i<=n;++i){
    			read(a[i]);if(a[i]>a[po])po=i;
    		}
    		int bo=0;
    		for(int i=1;i<n;++i){
    			int u,v;read(u),read(v);if(v==po)u^=v^=u^=v;
    			if(u==po&&(a[v]>a[bo]||(a[v]==a[bo]&&v<bo)))bo=v;
    		}
    		if(!bo)write(po);
    		else{
    			int delta=a[po]-a[bo];
    			if(m<delta)write(po);
    			else{
    				m-=delta;
    				if(po>bo)po^=bo^=po^=bo;
    				if(m&1)write(bo);else write(po);
    			}
    		}
    		pc('
    ');
    	}
    	return 0;
    }
    
    

    C 「MCOI-03」括号

    题目分析

    (k=0) 的时候,可以通过一个栈来求答案,不断删去匹配括号最后留下的串肯定是 )))...))((...((( ,答案就是这个串的长度,下面只考虑 (k>0) 的情况。

    考虑 (S(l,r)) 的 0 级偏值给答案造成贡献时需要乘以的系数,要从串 (S(1,n)) 得到 (S(l,r)) 左端点需要向右边移动 (l-1) 次,右端点需要向左边移动 (n-r) 次,这些移动都是在 (k) 步里面完成的,由隔板法就可以得出要乘上的系数就是 ({l-1+k-1choose k-1} imes {n-r+k-1choose k-1}) ,不妨设 (S(l,r)) 的 0 级偏值等于 (T(l,r)) ,那么答案就是 (sum_{l=1}^nsum_{r=l}^n(T(l,r) imes {l-1+k-1choose k-1} imes {n-r+k-1choose k-1}))

    如何统计所有的 (S(l,r)) ?考虑从右边往左边扫,由 (sum_{r=l+1}^n(T(l+1,r) imes {n-r+k-1choose k-1})) 递推得出 (sum_{r=l}^n(T(l,r) imes {n-r+k-1choose k-1}))

    首先需要知道,如果固定左端点,随着右端点的增加,不断删去匹配括号得到的串 )))...))((...((( 中的左半部分(即 )))...)) )的长度一定会不断增加,那么我们删去匹配括号最终保留的串肯定是这样的:

    )))(...((
    )))(...((
    )))(...((
    ))(...((
    ))(...((
    ))(...((
    )(...((
    (...((
    (...((
    .
    .
    .
    (
    

    假如左边添加了一个 )

    ))))(...((
    ))))(...((
    ))))(...((
    )))(...((
    )))(...((
    )))(...((
    ))(...((
    )(...((
    )(...((
    .
    .
    .
    )(
    )
    

    只是每个串的长度增加了 (1) ,所以此时满足:

    [sum_{r=l}^n(T(l,r) imes {n-r+k-1choose k-1})=sum_{r=l}^n{n-r+k-1choose k-1}+sum_{r=l+1}^n(T(l+1,r) imes {n-r+k-1choose k-1}) ]

    假如左边添加了一个 (

    ()))(...((
    ()))(...((
    ()))(...((
    ())(...((
    ())(...((
    ())(...((
    ()(...((
    ((...((
    ((...((
    .
    .
    .
    ((
    (
    

    此时可能出现匹配括号,需要把匹配括号删去:

      )(...((
      )(...((
      )(...((
      (...((
      (...((
      (...((
      (...((
    ((...((
    ((...((
    .
    .
    .
    ((
    (
    

    不难发现,所有原本存在 ) 的子串的长度都减小了 (2) ,不妨设最小的满足 (S(l+1,r)) 左边保留了一个 )(r)(p) ,那么可以得到:

    [sum_{r=l}^n(T(l,r) imes {n-r+k-1choose k-1})=sum_{r=l}^n{n-r+k-1choose k-1}-2sum_{r=p}^n{n-r+k-1choose k-1}+sum_{r=l+1}^n(T(l+1,r) imes {n-r+k-1choose k-1}) ]

    由此我们可以得出,我们需要维护的就是 ) 数量不同的所有断点,不难发现这个是很好维护的,用一个栈维护就行了,时间复杂度 (mathcal O(n+k))

    参考代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ch() getchar()
    #define pc(x) putchar(x)
    template<typename T>inline void read(T&x){
    	int f;char c;
    	for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
    	for(x=0;c<='9'&&c>='0';c=ch())x=x*10+(c&15);x*=f;
    }
    template<typename T>inline void write(T x){
    	static char q[64];int cnt=0;
    	if(!x)pc('0');if(x<0)pc('-'),x=-x;
    	while(x)q[cnt++]=x%10+'0',x/=10;
    	while(cnt--)pc(q[cnt]);
    }
    const int mod=998244353,maxn=2000005;
    int mo(const int x){
    	return x>=mod?x-mod:x;
    }
    int fac[maxn],iac[maxn];
    int binom(int n,int m){
    	return 1ll*iac[m]*iac[n-m]%mod*fac[n]%mod;
    }
    char s[maxn];
    int st[maxn],tp;
    int main(){
    	int n,k;read(n),read(k);
    	if(k==0){
    		scanf("%s",s+1);
    		int now=0,ans=0;
    		for(int i=1;i<=n;++i){
    			if(s[i]==')'){
    				if(now)--now;
    				else ++ans;
    			}
    			else ++now;
    		}
    		ans+=now;
    		write(ans),pc('
    ');
    	}
    	else{
    		int mx=n+k;
    		iac[0]=iac[1]=fac[0]=fac[1]=1;
    		for(int i=2;i<=mx;++i)
    			iac[i]=1ll*(mod-mod/i)*iac[mod%i]%mod;
    		for(int i=2;i<=mx;++i)
    			fac[i]=1ll*fac[i-1]*i%mod,iac[i]=1ll*iac[i-1]*iac[i]%mod;
    		scanf("%s",s+1);
    		int ans=0,sum=0,all=0;
    		for(int i=n;i>=1;--i){
    			sum=mo(sum+binom(n-i+k-1,k-1));
    			all=mo(all+sum);
    			if(s[i]=='('){
    				if(tp){
    					all=mo(mo(mo(mod-st[tp])<<1)+all);--tp;
    				}
    			}
    			else{
    				++tp;st[tp]=sum;
    			}
    			ans=mo(ans+1ll*all*binom(i-1+k-1,k-1)%mod);
    		}
    		write(ans),pc('
    ');
    	}
    	return 0;
    }
    
    

    总结

    这次月赛没有打多久,这个成绩勉强满意吧。

  • 相关阅读:
    Linux各目录的意义
    LinuxVIM编辑器用法
    Linux自动同步时间
    bash的基本特性
    shell-homeworkone
    shell
    笔记
    Python-1-Day
    Linux使用BIND提供域名解析服务
    Linuxautofs自动挂载服务
  • 原文地址:https://www.cnblogs.com/lsq147/p/13907214.html
Copyright © 2020-2023  润新知