2019 CCPC 女生赛

题目链接

Rank:67 / 297  (不过榜单好像不是现场的榜单)

这次韩巍有课没来,我和程磊两个人做的,这次做的是女生赛,沃老师出的题,题面都是中文题,比较友好,题目都比较简单,都是思维题,一共做出来6个题(终于破了做不出第六题的魔咒......)

HDU 6544 

签到题。

HDU 6545

签到题。写出前几项找规律就行了。

HDU 6550

签到题。可以发现,当第n+1个点是“圆心和某两个点之间的中点的连线与圆的交点”时面积最大,推公式就行了。

HDU 6553

推公式。第一次加6,第二次加7,第三次加8......

HDU 6554

只有当n和m都是4的倍数的时候才能拼凑成,至于怎么拼成,把样例一粘就行了。

HDU 6551

这个题我过的时候感觉还挺惊奇的......就是把这n个时间看作n个点,每个点的值就是把时刻转换成秒(如果小时大于等于12,那么就让h-=12),然后每个点连出去两条边,构成一个n个点n条边的环,然后初始时刻往环里切入,至于从哪切入,for一遍取最小值就是答案。刚才说的每个点都向外连两条边是连向离它最近的两个点连边,每条边的大小就是顺时针和逆时针到达那个点的的距离取最小值。说的不太清楚,反正就这样。

ACcode:

#include<bits/stdc++.h>
typedef long long ll;
const ll N=90000;
const ll inf=1e15+10;
using namespace std;
ll n,H,M,S;
ll h[N],m[N],s[N];
ll a[N],b[N];
int main()
{
    while(scanf("%lld",&n)!=EOF)
    {
        scanf("%lld%lld%lld",&H,&M,&S);
        if(H>=12)
            H-=12;
        ll num=H*3600+M*60+S;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld%lld",&h[i],&m[i],&s[i]);
            if(h[i]>=12)
                h[i]-=12;
            a[i]=h[i]*3600+m[i]*60+s[i];
        }
        ll ans=inf;
        if(n==1)
        {
            if(num>a[1])
                ans=min(num-a[1],a[1]+12*3600-num);
            else
                ans=min(a[1]-num,num+12*3600-a[1]);
            double anss=ans;
            anss*=6;
            printf("%.2f\n",anss);
            continue;
        }
        sort(a+1,a+n+1);
        for(int i=1;i<=n-1;i++)
            b[i]=min(a[i+1]-a[i],a[i]+12*3600-a[i+1]);
        b[n]=min(a[n]-a[1],a[1]+12*3600-a[n]);
        ll sum=0;
        for(int i=1;i<=n;i++)
            sum+=b[i];
        for(int i=1;i<=n;i++)
        {
            if(a[i]>num)
            {
                if(i==1)
                    ans=min(ans,min(a[i]-num,num+12*3600-a[i])+sum-max(b[1],b[n]));
                else
                    ans=min(ans,min(a[i]-num,num+12*3600-a[i])+sum-max(b[i],b[i-1]));
            }
            else
            {
                if(i==1)
                    ans=min(ans,min(num-a[i],a[i]+12*3600-num)+sum-max(b[1],b[n]));
                else
                    ans=min(ans,min(num-a[i],a[i]+12*3600-num)+sum-max(b[i],b[i-1]));
            }
        }
        double anss=ans;
        anss*=6;
        printf("%.2f\n",anss);
    }
    return 0;
}

 HDU 6547

树链刨分+线段树区间开方区间求和模板题。

详见一下两篇博客:

https://blog.csdn.net/flyzer/article/details/102487521

https://blog.csdn.net/flyzer/article/details/102477838

HDU 6546

啊,这个题就是贪心一下(感觉这场题都很妙)。

f(x+1)-f(x)=a*(x+1)*(x+1)+b*x+c-(a*x*x+b*x+c)=a*(2*x+1)+b。

然后用set存,每次贪心的选择增加的最少的那个。详见代码。

#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
#define IT set<nodee>::iterator
typedef long long ll;
const ll inf=0x3f3f3f3f;
const ll N=100010;
using namespace std;
ll n,m;
struct node{
    ll a,b,c;
}e[100010];
struct nodee{
    ll id;
    ll num;
    bool operator < (const nodee& bb)const{
        if(num!=bb.num)
            return num<bb.num;
        if(num==bb.num)
            return id<bb.id;
        //这里这么写是因为:不能有重复的元素,因为set是去重的,但我不想让它去重
        //return num<bb.num;
    }
}d[100010];
ll cnt[100010];
set<nodee> s;
int main()
{
    mem(cnt,0);
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        for(ll i=1;i<=n;i++)
            scanf("%lld%lld%lld",&e[i].a,&e[i].b,&e[i].c);
        for(ll i=1;i<=n;i++)
        {
            d[i].id=i;
            d[i].num=e[i].a*(2*1+1)+e[i].b;
            s.insert(d[i]);
            cnt[i]++;
        }
        m-=n;
        while(m--)
        {
            IT it=s.begin();
            ll id=(*it).id;
            cnt[id]++;
            s.erase(it);
            nodee itt=(*it);
            itt.num=e[id].a*(cnt[id]*2+1)+e[id].b;
            s.insert(itt);
        }

        ll ans=0;
        for(ll i=1;i<=n;i++)
            ans+=e[i].a*cnt[i]*cnt[i]+e[i].b*cnt[i]+e[i].c;
        printf("%lld\n",ans);
        for(int i=1;i<=n;i++)
            cnt[i]=0;
    }
    return 0;
}

HDU 6549

额,dp,尽管沃老师在camp上讲过了,当时我好像会了,然后又不会了......

这个题有点奇葩,同样的代码,交几遍,有时候AC,有时候T,好像其他人对这个题也是这样。

这篇博客讲的挺好的:https://www.cnblogs.com/kangkang-/p/11642022.html

下面是我有时候AC有时候T的代码:

#include<bits/stdc++.h>
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<<endl<<endl<<endl
typedef long long ll;
const int inf=1e8;
const int N=100010;
using namespace std;
int n,l,k;
int dp[N][28][12],pre[N][28][12],suf[N][28][12];
char a[N];
void init()
{
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=27;j++)
            for(int p=0;p<=k+1;p++)
                dp[i][j][p]=inf,pre[i][j][p]=inf,suf[i][j][p]=inf;
}
int main()
{
    scanf("%d%d%d",&n,&l,&k);
    scanf("%s",a+1);
    init();
    for(int j=1;j<=26;j++)
    {
        if(a[1]-'a'+1==j)
            dp[1][j][1]=0;
        else
            dp[1][j][1]=1;
    }
    for(int j=1;j<=26;j++)
        for(int p=1;p<=k;p++)
            pre[1][j][p]=min(pre[1][j-1][p],dp[1][j][p]);
    for(int j=26;j>=1;j--)
        for(int p=1;p<=k;p++)
            suf[1][j][p]=min(suf[1][j+1][p],dp[1][j][p]);
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=26;j++)
            for(int p=1;p<=k;p++)
            {
                if(a[i]==j+'a'-1)
                    dp[i][j][p]=min(min(dp[i-1][j][p],pre[i-1][j-1][p-1]),suf[i-1][j+1][p-1]);
                else
                    {int q=max(i-l,1);dp[i][j][p]=min(min(dp[q][j][p],pre[q][j-1][p-1]),suf[q][j+1][p-1])+1;}
            }
        for(int j=1;j<=26;j++)
            for(int p=1;p<=k;p++)
                pre[i][j][p]=min(pre[i][j-1][p],dp[i][j][p]);
        for(int j=26;j>=1;j--)
            for(int p=1;p<=k;p++)
                suf[i][j][p]=min(suf[i][j+1][p],dp[i][j][p]);
    }
    int ans=inf;
    for(int j=1;j<=26;j++)
        for(int p=1;p<=k;p++)
            ans=min(ans,dp[n][j][p]);
    printf("%d\n",ans);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值