[51Nod]NOIP2018提高组省一冲奖班模测训练(三) 题解

链接

A.Anan的派对

题意:Anan想举办一个派对。Anan的朋友总共有 n 人。第i个人如果参加派对会得到 \(c_i\) 的快乐值,除他自己外每多一个人参加他会减少 \(d_i\) 的快乐值。Anan想让这个派对的总快乐值尽可能大,在这个基础上,能来的人越多越好。Anan想知道最佳的邀请方案的快乐值与参加人数。对于 \(50\%\) 的数据 , $n\le 1000 $

假设来的人的集合为 \(S\),则快乐值为 \(\sum_{i\in S}c_i-(|S|-1)\times d_i\)

枚举集合大小,然后排序选前 \(|S|\) 个即可

#include<stdio.h>
#include<algorithm>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
struct node{
    int c,d;
}a[1002];
int n,cnt;
long long ans=-1e18,r;
int main(){
    scanf("%d",&n);
    REP(i,1,n)scanf("%d",&a[i].c);
    REP(i,1,n)scanf("%d",&a[i].d);
    REP(t,1,n){
        std::sort(a+1,a+1+n,[&](const node&a,const node&b){return a.c-1ll*a.d*(t-1)>b.c-1ll*b.d*(t-1);});
        r=0;
        REP(i,1,t)r+=a[i].c-1ll*a[i].d*(t-1);
        if(r>=ans)ans=r,cnt=t;
    }
    printf("%lld\n%d\n",ans,cnt);
    return 0;
}

B.XYG的蛋糕

题意:一个 \(n\times m\) 的矩形,需要把它分成 \(1\times 1\) 的小块,每次选出已经分出的某一个矩形,切一刀,可以横切或竖切。求方案数,两个切法不同当且仅当其中一个切法中存在一条刀痕,在另一个切法中不存在。 \(n,m\le 300\)

考虑DP,设 \(dp[i][j]\) 表示大小为 \(i\times j\) 的矩形的方案数,第一反应是

\(dp[i][j]=\sum_x dp[x][j]\times dp[i-x][j]+\sum_ydp[i][y]\times dp[i][j-y]\)

但是这样有重复

增加一维 \(k\) 表示允不允许横切或竖切即可

#include<stdio.h>
#include<cstring>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
const int p=998244353;
int f[305][305][3];
inline int dfs(int x,int y,int z){
    if(x==1&&y==1)return 1;
    int&ans=f[x][y][z];
    if(~ans)return ans;
    ans=0;
    if(z!=1)REP(i,1,x-1)ans=(ans+1ll*dfs(i,y,1)*dfs(x-i,y,0))%p;
    if(z!=2)REP(i,1,y-1)ans=(ans+1ll*dfs(x,i,2)*dfs(x,y-i,0))%p;
    return ans;
}
int main(){
    memset(f,-1,sizeof f);
    int n,m;scanf("%d%d",&n,&m);
    printf("%d\n",dfs(n,m,0));
    return 0;
}

C.WZD的洞洞

题意:平面上有n个物品,每个物品有坐标xi,yi和价值wi,WZD希望用洞洞包含住价值尽可能高的物品。由于洞洞的构造,其两条边必须平行于坐标轴,且直角在左下方(也就是说,洞洞只能平行移动),并且要求直角必须恰好落在一个物品上。求洞洞能包含住最大价值为多少的物品。n≤100000,0<xi,yi≤10000,-10000<wi<10000。

这个直角三角形只能平行移动,这意味着它的斜边的斜率是不变的,而且题目要求直角顶点一定在一个物品上,所以如果用斜率为斜边的斜率的直线扫,顶点在一个物品上的三角形能包含另外一个物品的条件是他们在这个直线间的距离小于三角形的高,因此two pointers搞一下,树状数组维护一下即可

#include<stdio.h>
#include<cmath>
#include<algorithm>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
const int N=1e5+5,S=10005;
struct BIT{
    int c[S],n;
    inline void add(int p,int x){for(;p<=n;p+=p&-p)c[p]+=x;}
    inline int ask(int p){int r=0;for(;p;p-=p&-p)r+=c[p];return r;}
}tx,ty;
int n,A,B;
struct node{int x,y,w;double d;}a[N];
inline void smax(int&x,const int&y){x<y?x=y:0;}
int main(){
    scanf("%d%d%d",&n,&A,&B);
    const double base=sqrt(A*A+B*B),maxd=A*B/base;
    REP(i,1,n){
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
        a[i].d=(double)(B*a[i].x+A*a[i].y)/base;
        smax(tx.n,a[i].x),smax(ty.n,a[i].y);
    }
    std::sort(a+1,a+1+n,[&](const node&a,const node&b){return a.d>b.d;});
    int l=1,sum=0,ans=0;
    REP(r,1,n){
        sum+=a[r].w;
        while(l<r&&a[l].d-a[r].d>maxd){
            tx.add(a[l].x,-a[l].w),ty.add(a[l].y,-a[l].w);
            sum-=a[l++].w;
        }
        tx.add(a[r].x,a[r].w),ty.add(a[r].y,a[r].w);
        smax(ans,sum-tx.ask(a[r].x-1)-ty.ask(a[r].y-1));
    }
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/HolyK/p/9892446.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值