Codeforces Round 501 (Div. 3)

目录

A. Points in Segments

B. Obtaining the String

C. Songs Compression

D. Walking Between Houses

E. Stars Drawing

F. Bracket Substring


A. Points in Segments

明显的差分即可

void solve(){
    
    cin>>n>>m;
    vector<int> a(m+5);
    while(n--){
    	int l,r; cin>>l>>r;
    	a[l]++,a[r+1]--;
    }
    vector<int> ans;
    for(int i=1;i<=m;i++){
    	a[i]+=a[i-1];
    	if(!a[i]) ans.push_back(i);
    }
    cout<<ans.size()<<endl;
    for(auto&v:ans) cout<<v<<' ';
    cout<<endl;
    return ;
}

B. Obtaining the String

直接暴力交换即可对最前面的进行交换然后接着操作

void solve(){
	cin>>n;
    string a,b; cin>>a>>b;
    string aa(a),bb(b);
    sort(aa.begin(),aa.end());
    sort(bb.begin(),bb.end());
    if(aa!=bb){
    	cout<<-1<<endl;
    	return ;
    }
    int ans=0;
    vector<int> res;
    for(int i=0;i<n;i++){
    	if(a[i]!=b[i]){
    		int pos=0;
    		for(int j=i+1;j<n;j++){
    			if(a[j]==b[i]){
    				pos=j;
    				break;
    			}
    		}
    		for(int j=pos;j>=i+1;j--){
    			a[j]=a[j-1];
    			res.push_back(j);
    		}
    	    ans+=pos-i;
    	}
    }
    cout<<ans<<endl;
    for(auto&v:res) cout<<v<<' ';
    return ;
}

C. Songs Compression

简单贪心,先全选然后逐渐删去变化最大的即可

void solve()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    	int x,y; cin>>x>>y;
    	sum+=x;
    	w[i]=y-x;
    }
    sort(w+1,w+1+n);
    for(int i=0;i<=n;i++){
    	sum+=w[i];
    	if(sum<=m){
    		cout<<i<<endl;
    		return ;
    	}
    }
    cout<<-1<<endl;
    
    return ;
}

D. Walking Between Houses

k次走完s,首先对于k>s||k*(n-1)<s特判掉,这个时候我们有一个平均数的思维,有些数比平均数多有些是恰好利用这个即可

LL n,s,k;
void solve(){
   
    cin>>n>>k>>s;
    if(k>s || k*(n-1)<s) return cout<<"NO"<<endl,void();
    
    LL ans = s/k,more = s%k;;
    ans ++ ;
    int ok = 0;
    int now = 1;
    cout<<"YES"<<endl;
    for(int i=1;i<=more;i++){
    	now+=(ok ? -ans : ans);
    	ok ^= 1;
    	cout<<now<<' ';
    }
    ans -- ;
    for(int i=1;i<=k-more;k--){
    	now+=(ok ? -ans : ans);
    	ok ^= 1;
    	cout<<now<<' ';
    }
    return ;

E. Stars Drawing

考虑到我们要找的数十字,一个十字的大小是由左右上下的点的数量决定的所以我们先预处理出来(可以双指针或者是直接继承的方式如下代码)每一个点左右上下连续的点的数量,然后星星就是枚举每一个点找四周最小的即可,接着对于处理这个点是否被使用过我们可以考虑使用二维差分即可

int h[M][M],l[M][M];
char s[M][M];
int L[M][M],R[M][M],up[M][M],down[M][M];
void solve(){
	    
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    		cin>>s[i][j];
    		
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    		if(s[i][j]=='*'){
    			L[i][j]=L[i][j-1]+(s[i][j-1]=='*');
    			up[i][j]=up[i-1][j]+(s[i-1][j]=='*');
    		}
    		
    	
    for(int i=n;i>=1;i--)
    	for(int j=m;j>=1;j--)
    		if(s[i][j]=='*'){
    			R[i][j]=R[i][j+1]+(s[i][j+1]=='*');
    			down[i][j]=down[i+1][j]+(s[i+1][j]=='*');
    		}
    
    vector<TUP> ans;
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
    		if(s[i][j]=='*'){
    			int num = min({L[i][j],R[i][j],up[i][j],down[i][j]});
    			if(num){
    				ans.push_back({i,j,num});
    				l[i][j-num]++,l[i][j+num+1]--;
    				h[i-num][j]++,h[i+num+1][j]--;
    			}
    		}
    	}
    }
    
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++){
    		l[i][j]+=l[i][j-1];
    		h[i][j]+=h[i-1][j];
    		
    	}
     
    
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++){
    		if(s[i][j]=='*' and !l[i][j] and !h[i][j]){
    			cout<<-1<<endl;
    			return ;
    		}
    	}	
    cout<<ans.size()<<endl;
    for(auto&[x,y,cnt]:ans) cout<<x<<' '<<y<<' '<<cnt<<endl;
    return ;
}

F. Bracket Substring

非常经典的目标字符串出现的题目,我们考虑使用kmp+dp处理,同时考虑这个题目的括号特性我们需要开一个维度来记录当前这个括号匹配到了即可,规定过括号为+1,右括号为负1即可

然后kmp处理出来ne,接着对每一个位置接"("还是")"进行处理,然后dp

我们定义dp为构造了i个,当前括号的匹配值是j,同时匹配到了第k个数

dp[i][j][k],只有j>0才可以接右括号

int dp[M][M][M];
int ne[M];
int g[M][2];

void KMP(){
	for(int i=2,j=0;i<=n;i++){
		while(j and s[i]!=s[j+1]) j=ne[j];
		if(s[i]==s[j+1]) j++;
		ne[i]=j;
	}	
	for(int i=0;i<m;i++){
		int l=i,r=i;
		while(l and s[l+1]!='(') l=ne[l];
		while(r and s[r+1]!=')') r=ne[r];
		if(s[l+1]=='(') l++;
		if(s[r+1]==')') r++;
		g[i][1]=l,g[i][0]=r;
	}
	g[m][0]=g[m][1]=m;
}
void solve(){
   
    cin>>n; 
    cin>>s; m=s.size();
    s=' '+s;
	KMP();
	
	dp[0][0][0]=1;
	
	for(int i=0;i<2*n;i++)
		for(int j=0;j<=n;j++)// 表示括号的
			for(int k=0;k<=m;k++){// 匹配到了第几个
				int v=dp[i][j][k];
				if(j) dp[i+1][j-1][g[k][0]]=(dp[i+1][j-1][g[k][0]]+v)%mod;
				dp[i+1][j+1][g[k][1]]=(dp[i+1][j+1][g[k][1]]+v)%mod;
			}
	cout << dp[2*n][0][m] << endl;
    return ;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值