2021春季个人赛-1 补题

G.Snake Rana

题意: 给出一张 n ∗ m n*m nm的地图和 k k k个点,求不包含这些点的所有子矩形。
分析: 先求出 n ∗ m n*m nm的所有子矩形,再根据容斥原理减去所有包含这 k k k个点的所有不合法的子矩形。
在一个 n ∗ m n*m nm的矩形中,长为 m m m,宽为 n n n,横向长度为 1 1 1的子矩形可以有 m m m种选法,长度为 2 2 2的子矩形可以有 m − 1 m-1 m1种选法,以此类推,那么横向则有 m + ( m − 1 ) + ( m − 2 ) + ⋯ + 1 = n ∗ ( n + 1 ) 2 m+(m-1)+(m-2)+\cdots+1=\frac{n*(n+1)}{2} m+(m1)+(m2)++1=2n(n+1)种选法,纵向则有 n + ( n − 1 ) + ( n − 2 ) + ⋯ + 1 = m ∗ ( m + 1 ) 2 n+(n-1)+(n-2)+\cdots+1=\frac{m*(m+1)}{2} n+(n1)+(n2)++1=2m(m+1)种选法,根据乘法计数原理,总数就为 n ∗ ( n + 1 ) ∗ m ∗ ( m + 1 ) 4 \frac{n*(n+1)*m*(m+1)}{4} 4n(n+1)m(m+1)
设每个不合法的所有子矩形的集合为 A 1 , A 2 , A 3 , ⋯   , A k A_1,A_2,A_3,\cdots,A_k A1,A2,A3,,Ak
根据容斥原理,最终结果为
n ∗ ( n + 1 ) ∗ m ∗ ( m + 1 ) 4 − ∑ i = 1 k ∣ A i ∣ + ∑ 1 ≤ i < j ≤ k ∣ A i ∩ A j ∣ − ∑ 1 ≤ i < j < l ≤ k ∣ A i ∩ A j ∩ A l ∣ + ⋯ + ( − 1 ) k + 1 ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A k ∣ \frac{n*(n+1)*m*(m+1)}{4}-\sum_{i=1}^{k} |A_i|+\sum_{1\le i< j\le k}^{}|A_i\cap A_j|-\sum_{1\le i< j< l\le k}^{}|A_i\cap A_j\cap A_l|+\cdots+(-1)^{k+1}|A_1\cap A_2 \cap \cdots \cap A_k| 4n(n+1)m(m+1)i=1kAi+1i<jkAiAj1i<j<lkAiAjAl++(1)k+1A1A2Ak
那么如何求 A 1 , A 2 , A 3 , ⋯   , A k A_1,A_2,A_3,\cdots,A_k A1,A2,A3,,Ak的个数?
n ∗ m n*m nm的矩形中,假设在枚举过程中从 k k k个点中选了 i i i个点,那么可以求出这 i i i个点围成的最小子矩形,进而求出所有包含这个最小子矩形的子矩形,计算方法是枚举所有在这个最小子矩形之外的点,设最小子矩形的两个点坐标为 ( m i n x , m i n y ) , ( m a x x , m a x y ) (minx,miny),(maxx,maxy) (minx,miny),(maxx,maxy),那么所有选法方案为 m i n x ∗ m i n y ∗ ( n − m a x x − 1 ) ( m − m a x y − 1 ) minx*miny*(n-maxx-1)(m-maxy-1) minxminy(nmaxx1)(mmaxy1)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int t,inf=1e9;
long long int n,m,k,x[N],y[N];
int main(){
    
    
	cin>>t;
	while(t--){
    
    
		cin>>n>>m>>k;
		for(int i=0;i<k;i++) cin>>x[i]>>y[i];
		long long int ans=n*(n+1)/2*m*(m+1)/2;
		for(int i=1;i<1<<k;i++){
    
    
			long long int minx=inf,miny=inf,maxx=-1,maxy=-1;
			int cnt=0;
			for(int j=0;j<k;j++){
    
    
				if(i>>j&1){
    
    
					minx=min(minx,x[j]);
					miny=min(miny,y[j]);
					maxx=max(maxx,x[j]);
					maxy=max(maxy,y[j]);
					cnt++;
				}
			}
			long long int res=minx*miny*(n-maxx+1)*(m-maxy+1);
			if(cnt&1) ans-=res;
			else ans+=res;
		}
		cout<<ans<<endl;
	}
}

I.Mirrored String II

题意: 给定一个长度不超过 1000 1000 1000的字符串,求出只包含 A , H , I , M , O , T , U , V , W , X , Y {A, H, I, M, O, T, U, V, W, X, Y} A,H,I,M,O,T,U,V,W,X,Y的最长回文子串
分析: 首先想到的是马拉车算法,但是一看长度为 1000 1000 1000,暴力就可以做。思路是先把不合法的字符串设为#,到时候特判一下就可以,把奇回文串和偶回文串的最大长度分别求出取 m a x max max就是答案

代码:

#include<bits/stdc++.h>
using namespace std;
string a;
int t;
int main(){
    
    
    cin>>t;
    while(t--){
    
    
        cin>>a;
        for(int i=0;i<a.size();i++){
    
    
            if(a[i]!='A'&&a[i]!='H'&&a[i]!='I'&&a[i]!='M'&&a[i]!='O'&&a[i]!='T'&&a[i]!='U'&&a[i]!='V'&&a[i]!='W'&&a[i]!='X'&&a[i]!='Y'){
    
    
                a[i]='#';
            }
        }
        int res=0;
        for(int i=0;i<a.size();i++){
    
    
            if(a[i]=='#') continue;
            int cnt=1,m=i,n=i;
            while(m-1>=0&&n+1<a.size()&&a[m-1]==a[n+1]&&a[m-1]!='#'&&a[n+1]!='#'){
    
    
                cnt+=2;
                m--,n++;
            }
            res=max(res,cnt);
        }
        for(int i=0,j=1;j<a.size();j++,i++){
    
    
            if(a[i]=='#'||a[j]=='#') continue;
            int cnt=2,m=i,n=j;
            if(a[m]!=a[n]) continue;
            while(m-1>=0&&n+1<a.size()&&a[m-1]==a[n+1]&&a[m-1]!='#'&&a[n+1]!='#'){
    
    
                cnt+=2;
                m--,n++;
            }
            res=max(res,cnt);
        }
        cout<<res<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/messywind/article/details/114370253