codeforces training8

1.cf26B Regular Bracket Sequence水题

题意:一串正反括号,去掉一些使剩下的序列合法并最长。

分析:一个栈即可解决问题。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 10000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
#define min(a,b) a<b?a:b
#define max(a,b) a<b?b:a
typedef unsigned long long ULL;
typedef long long LL;
using namespace std;
char str[1000005];
int main()
{
    scanf("%s",str);
    int len=0;
    int now=0;
    for(int i=0;i<strlen(str);i++)
    {
        if(str[i]==')'&&now==0)
            continue;
        if(str[i]=='(')
        {
            now++;
            len++;
        }
        else
        {
            now--;
            len++;
        }
    }
    printf("%d\n",len-now);
    return 0;
}




2.cf25C Roads in Berland 

题意:有n个城市,每个城市都可到达其他任意城市并知道最短距离,先依次在两城市之间修建新的路,每修建一条路,输出此时所有对城市的距离之和。

分析:若在a,b间修建的新城市x小于原先d[a][b],根据floyed算法的思想,用两个for更新d,d[i][j]=min(d[i][j],d[i][a]+x+d[b][j]),d[i][j]=min(d[i][j],d[i][b]+x+d[a][j。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 10000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
typedef pair<int,int> pii;
const int maxn=305;
int d[maxn][maxn];
int n,q;
int main()
{
    scanf("%d",&n);
    LL ans=0;
    int a,b,w;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&d[i][j]);
            ans+=d[i][j];
        }
    }
    scanf("%d",&q);
    for(int f=1;f<=q;f++)
    {
        scanf("%d%d%d",&a,&b,&w);
        if(w<d[a][b])
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                d[i][j]=min(d[i][j],d[i][a]+w+d[b][j]);
                d[i][j]=min(d[i][j],d[i][b]+w+d[a][j]);
            }
        }
        ans=0;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
            ans+=d[i][j];
        if(f==q)
            printf("%lld\n",ans);
        else
            printf("%lld ",ans);
    }
    return 0;
}

3.cf25D Roads not only in Berland 并查集

题意:有n个城市,n-1条路,现在要使所有城市都联通,但每修一条新路就要去掉一条现有路,输出修路数目,拆掉的路的两端点和新建的路的两端点。

分析:n-1条路恰好可以使所有城市联通,输入时用并查集判断不需要的路并记录,图被分为几个不连通的连通块,可用并查集找出每一个连通块的一个城市节点(父节点即可),问题就解决了。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 10000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
#define min(a,b) a<b?a:b
#define max(a,b) a<b?b:a
typedef unsigned long long ULL;
typedef long long LL;
const int maxn=1005;
using namespace std;
int n;
int p[maxn];
int bian[maxn][2];
int find(int x)
{
    return p[x]==x?x:p[x]=find(p[x]);
}
bool un(int i,int j)
{
    int x=find(i);
    int y=find(j);
    if(x==y)
        return false;
    p[x]=y;
    return true;
}
int main()
{
    scanf("%d",&n);
    int a,b;
    int e=0;
    int mm[maxn];
    bool vis[maxn];
    memset(vis,0,sizeof(vis));
    int f=0;
    for(int i=1;i<=n;i++)
        p[i]=i;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        if(!un(a,b))
        {
            bian[e][0]=a;
            bian[e++][1]=b;
        }
    }
    for(int i=1;i<=n;i++)
    {
        int op=find(i);
        if(vis[op])
            continue;
        vis[op]=1;
        mm[f++]=op;
    }
    printf("%d\n",e);
    for(int i=0;i<e;i++)
    {
        printf("%d %d %d %d\n",bian[i][0],bian[i][1],mm[i],mm[i+1]);
    }
    return 0;
}

4.cf28B Party 数学题

题意:宴会上有n个人,没有朋友的走,在剩下的人里有一个朋友的走,在剩下的人里两个朋友的走.......,最后剩下最多多少人不用走。

分析:最好的情况是这样,n个人中,2个人互相不是朋友,这两个人与其余n-2个人都是朋友,则他们有n-2个朋友,其余n-2个人互相都是朋友,他们有n-1个朋友,2个n-2个朋友的先走,剩下的人从n-1个朋友变成了n-2个朋友,因此他们都不用走。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 10000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
#define min(a,b) a<b?a:b
#define max(a,b) a<b?b:a
typedef unsigned long long ULL;
typedef long long LL;
const int maxn=100005;
using namespace std;
int main()
{
    int t;
    int n;
    scanf("%d",&t);
    for(int i=0;i<t;i++)
    {
        scanf("%d",&n);
        if(n==1)
            printf("0\n");
        else
            printf("%d\n",n-2);
    }
    return 0;
}

5.cf25E Test KMP

题意:3个字符串拼接成一个串,3个字符串都是这个字符串的字串,并使这个字符串最短。

分析:可枚举拼接顺序(只有6种,123,132,213,231,312,321),kmp见代码。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 10000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
#define min(a,b) a<b?a:b
#define max(a,b) a<b?b:a
typedef unsigned long long ULL;
typedef long long LL;
const int maxn=100005;
using namespace std;
char s[3][maxn];
int next[3][maxn];
void get_next(int i)//构造next数组,next[i]存的是字符串下标0-(i-1)的相同前缀后缀最长长度
{
    int len=strlen(s[i]);
    int k=-1,j=0;
    next[i][0]=-1;
    while(j<len-1)
    {
        if(k==-1||s[i][k]==s[i][j])//匹配
        {
            k++;j++;
            next[i][j]=k;
        }
        else
            k=next[i][k];//不匹配,寻找更短的相同前缀后缀
    }
}
int kmp(char* p,int f)
{
    int len1=strlen(p);
    int len2=strlen(s[f]);
    int i=0,j=0;
    while(i<len1&&j<len2)
    {
        if(j==-1||p[i]==s[f][j])
        {
            i++;
            j++;
        }
        else
            j=next[f][j];
    }
    return j;//若匹配成功,说明s[f]是p的字串,j==strlens[f];否则,
            //j表示的是s[f]的前缀与p的后缀重合的字符数。
}
int solve(int i,int j,int k)
{
    char str[maxn*3];
    str[0]='\0';
    int d=kmp(s[i],j);
    strcat(str,s[i]);
    strcat(str,s[j]+d);//拼接s[i]和s[j],除去公共部分
    d=kmp(str,k);
    strcat(str,s[k]+d);//拼接上s[k]
    return strlen(str);
}
int main()
{
    scanf("%s%s%s",s[0],s[1],s[2]);
    for(int i=0;i<3;i++)
        get_next(i);
    int mi=inf;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        for(int k=0;k<3;k++)
        if(i!=j&&j!=k&&i!=k)
        mi=min(mi,solve(i,j,k));
    cout<<mi<<endl;
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值