比赛链接点击打开链接
A题
题意 给定一个由左右小括弧组成的串,通过删除某些括弧,求剩下的括弧能够获得的最长合法长度。
思路:类似求合法括弧的题目,之前做过一些,也有了一些经验。首先,从左往右扫,两个变量rest和cnt ,遇到“(” ,rest++,否则rest--,cnt++。若rest<0 说明这个括弧要删除。同理,从右往左再扫一遍。求两次的最大值即可。
开始的时候没读清题意,以为是老题WA了。。。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll ;
const int inf = 1<<29;
char a[1000005];
int main()
{
cin>>a;
int n=strlen(a),i;
int cnt1=0,cnt2=0;
int rest=0;
for(i=0; i<n; i++)
{
if(a[i]=='(')
{
rest++;
}
else if(a[i]==')')
{
rest--;
if(rest>=0)
{
cnt1++;
}
}
if(rest<0)
{
rest=0;
}
}
rest=0;
for(i=n-1; i>=0; i--)
{
if(a[i]==')')
{
rest++;
}
else if(a[i]=='(')
{
rest--;
if(rest>=0)
{
cnt2++;
rest--;
}
}
if(rest<0)
{
rest=0;
}
}
cout<<max(cnt1,cnt2)*2<<endl;
return 0;
}
B题
题意:给定一个矩阵d,d[i][j]代表初始i和j之间的最短路。现在要在某些点间建一些新的路径。求建到第i条路径时,任意两点之间最短路的和。
用类似floyed求最短路的思想。简单回顾一下floyed求最短路。其基本思想是dp,对于从i到j的路径,走点k和不走点k。那么这道题从i到j,对于新建的路,走还是不走。
注意输入数据中,新建的路有可能比之前的路要长。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll ;
const int inf = 1<<29;
const int maxn=305;
int d[maxn][maxn];
int main()
{
int n,m,i,j,a,b,c;
cin>>n;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
cin>>d[i][j];
}
cin>>m;
while(m--)
{
cin>>a>>b>>c;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
d[j][i]=d[i][j]=min(d[i][j],d[i][a]+d[b][j]+c);
d[j][i]=d[i][j]=min(d[i][j],d[i][b]+d[a][j]+c);
}
}
ll ans=0;
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
ans+=d[i][j];
}
}
cout<<ans<<" ";
}
return 0;
}
C题
题意 输入一些路径。让你删除一些路径的同时再添加一些路径,使得每两个点之间都可以到达。
思路:并查集。输入路径时,判断两点是否处于同一个集合,若在,当前这条路就可以删除。否则,这条路径就要保留。
然后再枚举两个任意点,判断是否在同一个集合中,若不在,两个点之间建路。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll ;
const int inf = 1<<29;
const int maxn=1005;
int del[maxn][2],add[maxn][2];
int parent[maxn];
void init(int n)
{
for(int i=1;i<=n;i++)
parent[i]=i;
}
int find_p(int p)
{
if(p==parent[p]) return p;
return parent[p]=find_p(parent[p]);
}
int main()
{
int n,i,j,x,y,cnt1=0,cnt2=0;
cin>>n;
init(n);
for(i=1;i<n;i++)
{
cin>>x>>y;
int fx=find_p(x),fy=find_p(y);
if(fx!=fy)
parent[fx]=fy;
else
{
del[cnt1][0]=x,del[cnt1++][1]=y;
}
}
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
int fi=find_p(i),fj=find_p(j);
if(fi!=fj)
{
parent[fi]=fj;
add[cnt2][0]=fi,add[cnt2++][1]=fj;
}
}
}
cout<<cnt1<<endl;
for(i=0;i<cnt1;i++)
{
cout<<del[i][0]<<" "<<del[i][1]<<" "<<add[i][0]<<" "<<add[i][1]<<endl;
}
return 0;
}
D题 机智题
题意:为了说清楚题意,我增加一个时间t。题意是这样的:t=0时,有零个朋友的人全部滚蛋。t=1时,对于剩下的人而言,有1个朋友的全部滚蛋……问最终人数稳定时,最多可能剩下多少人。
思路:因为时间是每次加1的。对于当前t,认识t+1个朋友的不会离开。这些人要想在t+1秒不离开,他们认识的人数就要发生突变,必然变成比t+1小的数,显然t-1是最大的数。对于n个人来说,显然n-2最大。那么怎么实现这种突变呢?假设1,2不认识,并且与n-2个人都认识,剩下n-2个人认识n-1个人,那么当t=n-2时,1和2走了,那么剩下的n-2个人瞬间从认识n-1个人变成认识n-3个人。当t=n-1时,已经没有认识n-1个人的人了。
因此,最终结果就是n-2,特判一下1就好。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll ;
const int inf = 1<<29;
int main()
{
int n;
int t;
cin>>t;
while(t--)
{
cin>>n;
if(n==1) cout<<0<<endl;
else cout<<n-2<<endl;
}
return 0;
}
E题
先来WA个坑。。。