罪的晚风,可曾带回朝露映的清纯?|

LarsWerner

园龄:4年11个月粉丝:20关注:3

【AtCoder】ABC 167

AtCoder Beginner Contest 167

A Registration

给两个字符串,长度为 nn+1。检查第二个字符串的前 n 位是不是第一个字符串。枚举一下每一位即可。

#include<bits/stdc++.h>
using namespace std;
string s,t;
int main(){
	cin>>s>>t;
	bool ans=1;
	for(int i=0;i<s.size();i++) if(s[i]!=t[i]) ans=0;
	cout<<(ans?"Yes":"No");
	return 0;
} 

B Easy Linear Programming

对于选出的 k 张卡片,肯定优先选择 1 的,再选 0 的,最后是 1 的。于是我们分类讨论即可,

#include<bits/stdc++.h>
using namespace std;
int n,m,x,y,z,ans;
int main(){
	cin>>x>>y>>z>>n;
	if(x>=n) ans=n;
	else if(x+y>=n) ans=x;
	else ans=x-(n-x-y);
	cout<<ans;
	return 0;
} 

C Skill Up

暴力枚举每一本书选不选,然后判断是否合法最后更新答案即可,

#include<bits/stdc++.h>
using namespace std;
const int N=109;
int n,m,x,c[N],a[N][N],p[N],ans=0x3f3f3f3f;
void dfs(int s,int price){
	if(s==n+1){
		for(int i=1;i<=m;i++) if(p[i]<x) return;
		ans=min(ans,price); 
		return;
	}
	dfs(s+1,price);
	for(int i=1;i<=m;i++) p[i]+=a[s][i];
	dfs(s+1,price+c[s]);
	for(int i=1;i<=m;i++) p[i]-=a[s][i];
}
int main(){
	cin>>n>>m>>x;
	for(int i=1;i<=n;i++){
		cin>>c[i];
		for(int j=1;j<=m;j++) cin>>a[i][j];
	}
	dfs(1,0);
	if(ans>1e9) cout<<-1;
	else cout<<ans;
	return 0;
}

D Teleporter

用dfs处理出环,然后分类讨论,国王有没有走到环上。由于走到换上就不会出来了,直接取模即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+9;
int n,k; bool vst[N],in[N]; int tot,sl,a[N],cnt,loop[N];
void dfs(int u){
	tot++; vst[u]=1; int v=a[u];
	if(vst[v]) sl=v;
	else dfs(v);
}
signed main(){
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	dfs(1); int u=sl; int find=0;
	while(1){
		if(u==sl&&find) break;
		find=1, loop[++cnt]=u, in[u]=1;
		u=a[u];
	} loop[0]=loop[cnt];
	if(k<=tot-cnt){
		int ans=1;
		for(int i=1;i<=k;i++) ans=a[ans];
		cout<<ans;
	}else{
		k++;
		cout<<loop[(k-(tot-cnt))%cnt];
	}
	return 0;

E Colorful Blocks

看到题立马想到一个 O(nk)dp…… 可惜这题是个组合题。

没关系,有 dp 可以找规律观察。f(i,j) 表示前 i 个格子有 j 对相等的。

f(i,j)=f(i1,j1)+f(i1,j)×(m1)

然后经过一系列的推导(我不会)和列式子观察(这个才是),我们发现每一个 f(i,j) 都是一个可以化作乘积的形式,常数项是 Ci1j,且都含有 mm1,其中 m 的指数是 1m1 的指数是一个连续递减数列,为 ij1。于是我们可以搞得式子:

f(i,j)=Ci1j×m×(m1)ij1

这个故事告诉我们:手动打表和多项式很重要

最后求出 f(n,j) 即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+9,mod=998244353;
int n,m,k,ans,fact[N],inv[N];
int qp(int a,int b=mod-2){
    return (b==0?1:(b%2?qp(a*a%mod,b/2)*a%mod:qp(a*a%mod,b/2)));
}
int C(int a,int b){return fact[a]*inv[b]%mod*inv[a-b]%mod;}
signed main(){
	scanf("%lld%lld%lld",&n,&m,&k);
	for(int i=0;i<=n;i++) fact[i]=(i==0?1:fact[i-1]*i%mod);
	for(int i=n;i>=0;i--) inv[i]=(i==n?qp(fact[n]):inv[i+1]*(i+1)%mod);
	for(int j=0;j<=k;j++){
		ans=(ans+m*C(n-1,j)%mod*qp(m-1,n-j-1))%mod;
	}
	printf("%lld",ans);
	return 0;
} 

F Bracket Sequencing

这题其实需要一个构造。按照想好的构造方案去弄,如果可行,那么就是Yes,否则就是No。

这题和这题有很大的相似之处。我们可以把左括号理解成回血,右括号理解为掉血。

这个字符串的前缀和(左括号为+1,右括号为-1)的最小值即可以理解为最大的耗血,最大值可以理解为最大的回血。

对于一个字符串,如果它的总和是非负的,我们肯定先打最小值最大的(即最小耗血)。

对于一个字符串,如果它的总和是负的,按照比赛讨论区的题解的说法,他们是对称的;按照上面那题的题解来说,我们可以反过来看,即右括号变成+1,左括号-1,那么显然应该从右往左选前缀最大值最小的,即从左往右看,后缀最大值最大的。

所以最后再统计一下即可。

int n,ac,bc;
struct str{int m;string st;}a[N],b[N];
bool cmp(const str&a,const str&b){return a.m>b.m;}
string last="";
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		string s; cin>>s;
		int sum=0,mx=-1e9,mn=1e9;
		for(int j=0;j<s.size();j++){
			if(s[j]=='(') sum++;
			else sum--;
			mn=min(mn,sum);
		} sum=0;
		for(int j=s.size()-1;j>=0;j--){
			if(s[j]=='(') sum++;
			else sum--;
			mx=max(mx,sum);
		}
		if(sum>=0) a[++ac]=(str){mn,s};
		else b[++bc]=(str){mx,s};
	}
	sort(a+1,a+ac+1,cmp), sort(b+1,b+bc+1,cmp);
	for(int i=1;i<=ac;i++) last+=a[i].st;
	for(int i=1;i<=bc;i++) last+=b[i].st;
	int sum=0;
	for(int i=0;i<last.size();i++){
		if(last[i]=='(') sum++;
		else sum--;
		if(sum<0) return puts("No"),0;
	}
	if(sum==0) puts("Yes");
	else puts("No");
	return 0;
}

本文作者:LarsWerner

本文链接:https://www.cnblogs.com/TetrisCandy/p/ABC167.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   LarsWerner  阅读(786)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起