组队赛第五场 组合隔板法+最小生成树预处理并查集+字符串哈希+边查询边插入的堆

UVALive 6434

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4445

这题正好就是大一小学期的时候好像是曦曦出的那个牛那题吧,就是要买多少块板然后正好把牛给拦完。这题也是一样,就是找最大的距离,当做隔板,依次把最大的距离去掉,最后的就是最小的了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
#define maxn 1010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int main()
{
    //freopen("test.txt","r",stdin);
    int t;
    scanf("%d",&t);
    for(int ii=1;ii<=t;ii++)
    {
        int n,m,i,sum=0,a[102];
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
            scanf("%d",a+i);
        sort(a,a+n);
        for(i=1;i<n;i++)
            a[i-1]=a[i]-a[i-1];
        sort(a,a+n-1);
        for(i=0;i<n-m;i++)
            sum+=a[i];
        printf("Case #%d: %d\n",ii,sum);
    }
    return 0;
}

UVALive 6437

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4448

这题刚开始我也没想好怎么做,因为找最小的,所以感觉和最小生成做有并。但是怎么有关的,想了好久,原来是预处理那里。先打发电站放进并查集里就行了,然后求出来的最小生成树肯定就是最小的啦。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
#define maxn 1010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct abc
{
    int u,v,w;
    bool operator<(const abc &a)const
    {
        return w<a.w;
    }
}a[40005];
int f[202],t,i,j,k,n,m,fa,power;
int find(int x)
{
    return x==f[x]?x:f[x]=find(f[x]);
}
int kruscal()
{
    sort(a,a+m);
    int sum=0;
    for(j=0;j<m;j++)
    {
        int x=find(a[j].u);
        int y=find(a[j].v);
        if(x!=y) sum+=a[j].w,f[y]=x;
    }
    return sum;
}
int main()
{
    //freopen("test.txt","r",stdin);
    scanf("%d",&t);
    for(i=1;i<=t;i++)
    {
        scanf("%d%d%d",&n,&m,&k);
        for(j=0;j<=n;j++)
            f[j]=j;
        scanf("%d",&fa);
        for(j=1;j<k;j++)
        {
            scanf("%d",&power);
            f[power]=fa;
        }
        for(j=0;j<m;j++)
            scanf("%d%d%d",&a[j].u,&a[j].v,&a[j].w);
        printf("Case #%d: %d\n",i,kruscal());
    }
    return 0;
}

UVALive 6439

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4450

思路:一看题就知道是哈希了,因为把后面的与前面的比较,如果相等就加2, 这样一直下去得到的肯定是最大的回文。然后第一发WA是忘了注释文件了,第二发WA是ABBBA这个例子没过,原来是while循环那写成了r1<l2了,改成r1<=l2才行,因为……这个不用解释了;然后交了还是WA,尼玛,神坑啊……然后别人都是用暴力做的,然后就想自己难道用哈希错了??然后又试了几个样列都对,就想了肯定哈希一定过,只是哪里错了。然后想啊想,想起以前有道哈希是因为种子的原因然后有冲突的时候,把种子131改成1313就过了,尼玛……真的有冲突!!!!

原来冲突是因为:以前写的131的种子的时候是写成hash[i]=hash[i-1]*seed+s[i]的,然后现在写成hash[i]=hash[i-1]*seed+s[i]-'A'+1;就起冲突了,所以得记住这个问题啊!!!教训啊!!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
#define maxn 50010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ull hash[maxn],base[maxn];
char s[maxn];
int main()
{
    //freopen("test.txt","r",stdin);
    int t,ii;
    for(ii=1,base[0]=1;ii<maxn;ii++)
        base[ii]=base[ii-1]*1313;
    scanf("%d",&t);
    for(ii=1;ii<=t;ii++)
    {
        scanf("%s",s);
        int i,len=strlen(s);
        if(len==1)
        {
            printf("Case #%d: 1\n",ii);
            continue;
        }
        for(i=1,hash[0]=0;i<=len;i++)
            hash[i]=hash[i-1]*1313+s[i-1]-'A'+1;
        int l1=0,r1=1,l2=len-1,r2=len,sum=0;
        while(r1<=l2)
        {
            ull hash1=hash[r1]-hash[l1]*base[r1-l1];
            ull hash2=hash[r2]-hash[l2]*base[r2-l2];
            if(hash1==hash2)
            {
                //cout<<l1<<' '<<r1<<' '<<l2<<' '<<r2<<endl;
                sum+=2,l1=r1,r2=l2;
            }
            r1++,l2--;
        }
        if(r1-l1>1||r2-l1==1) sum++;
        printf("Case #%d: %d\n",ii,sum);
    }
    return 0;
}

UVALive 6440

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4451

思路:这题刚才开始看的时候,就觉得应该是用堆做了,因为是取最优的,就是取最小或者最大的,这正好符合堆的性质。但是该怎么修改堆里面的东西呢,就是这里我没想明白,以前也没有遇到过这种边修改边查询的堆,然后……就没有然后了……不机智啊!

想了好久,实在不行了,就看了下题解,原来很简单的思想,把所有的都初始为时间0,就是同一个起点了,然后就好比较了。同一个速率放同一堆里就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
#define maxn 50010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int main()
{
    //freopen("test.txt","r",stdin);
    int t,ii;
    scanf("%d",&t);
    for(ii=1;ii<=t;ii++)
    {
        int n,t,s,r;
        char str[2];
        priority_queue<int,vector<int>,less<int> >q[101];
        scanf("%d",&n);
        printf("Case #%d:\n",ii);
        while(n--)
        {
            scanf("%s%d",str,&t);
            if(str[0]=='P')
            {
                scanf("%d%d",&s,&r);
                q[r].push(s-r*t);
            }
            else
            {
                ll Max=0,ans;
                for(int i=0;i<101;i++)
                    if(!q[i].empty())
                    {
                        ll MM=(ll)i*(ll)t+(ll)q[i].top();
                        if(MM>=Max) ans=i,Max=MM;
                    }
                q[ans].pop();
                printf("%lld %d\n",Max,ans);
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值