CCPC-Wannafly Winter Camp Day1 (Div2)

比较水的题或者现在补了我以后还是不会的题我就不补了qwq对不起我比较懒

目录

B 吃豆豆

C 拆拆拆数

F 爬爬爬山

J 奇兵夺宝


B 吃豆豆

【题目】

【解题思路】

这种当前结果与之前的结果有关的 题应该首先想到dp的……然而当时可能脑袋坏掉了,并没有做粗来。

设dp[i][j][k]为在第k秒( i , j )这个位置获得的最多的糖果数,然后由四个方向再自己转移一下即可。

转移方程为:dp[i][j][k]=max({dp[i-1][j][k-1],dp[i][j+1][k-1],dp[i+1][j][k-1],dp[i][j-1][k-1],dp[i][j][k-1]})+(k%mp[i][j]==0?1:0)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=10200;//当每个10s出现一个糖果,需要1018个糖果时达到时间的最大值10180
int mp[20][20],dp[20][20][maxn];
int main()
{
    int n,m,C,xs,xt,ys,yt;
    scanf("%d%d%d",&n,&m,&C);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&mp[i][j]);
    scanf("%d%d%d%d",&xs,&ys,&xt,&yt);
    memset(dp,-INF,sizeof(dp));
	dp[xs][ys][0]=0;    			
    for(int k=1;k<maxn;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                dp[i][j][k]=max({dp[i-1][j][k-1],dp[i][j+1][k-1],dp[i+1][j][k-1],dp[i][j-1][k-1],dp[i][j][k-1]})+(k%mp[i][j]==0?1:0);
            }
        }
    }
    int ans=-1;
    for(int i=0;i<maxn;i++)
    {
        if(dp[xt][yt][i]>=C)
        {
            ans=i;
            break;
        }
    }
    printf("%d\n",ans);

}

C 拆拆拆数

【题目】

【解题思路】

可以证明肯定有解,至于怎么证明我也不造……

当A和B互质时直接输出这两个数即可。

当A和B不互质时,直接暴力找,但是A和B的数据范围是比较大的,如果暴力到数据上限是会TLE的,这里只要遍历到100就绰绰有余了,至于为什么我也不造……

【代码】

思路比较简单,就不贴代码了。

F 爬爬爬山

【题目】

【解题思路】

下山加体力,上山减体力,这道题目的关键在于要明白下山获得的体力在他下一次上山的时候就会全部用掉,所以下山获得的体力最终是抵消掉的,所以只需要将初始山高与初始体力和与每座山比较,预处理每两座山之间的总长度,比这个高度小的山两山之间的距离即是原路程,否则则需要把当前山降到初始山高与初始体力之和,再加上原路程,跑一次最短路即可(这里需要用队列优化dijkstra)。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+5;
LL h[maxn],dis[maxn];
bool vis[maxn];
int head[maxn*10],n,m,k,cnt=0;
struct Edge
{
    int v,next;
    LL w;
}edge[maxn*10];
struct Node
{
    int u;
    LL dis;
    bool operator < (const Node &a)const
    {
        return dis>a.dis;
    }
};
void add(int u,int v,LL w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void dijkstra(int start)
{
    priority_queue<Node>pq;
    for(int i=1;i<=n;i++)
        vis[i]=false,dis[i]=INF;
    Node t;
    t.u=start;t.dis=0;
    pq.push(t);
    dis[start]=0;
    while(!pq.empty())
    {
        int u=pq.top().u;
        pq.pop();
        if(!vis[u])
        {
            vis[u]=1;
            for(int i=head[u];i>=0;i=edge[i].next)
            {
                int v=edge[i].v;
                if(dis[v]>dis[u]+edge[i].w)
                {
                    dis[v]=dis[u]+edge[i].w;
                    t.u=v;t.dis=dis[v];
                    pq.push(t);
                }
            }
        }
    }
}
int main()
{
    int u,v,w;
    scanf("%d%d%d",&n,&m,&k);
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)scanf("%lld",&h[i]);
    int t=h[1]+k;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w+max(0LL,h[v]-t)*max(0LL,h[v]-t));
        add(v,u,w+max(0LL,h[u]-t)*max(0LL,h[u]-t));
    }
    dijkstra(1);
    printf("%lld\n",dis[n]);
}

J 奇兵夺宝

【题目】

【解题思路】

贪心,先预处理数据,将每个居民拥有的宝物按照所花费的金币从小到大排序。

枚举wls买到的宝物数量,假设为i,那么遍历每个居民,当其拥有的宝物数大于i时wls需要买,如果买到的宝物数之和仍然小于i,那么需要继续用花费较少的宝物补充。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
typedef long long LL;
const LL INF=0x3f3f3f3f3f3f3f3f;;
struct Node
{
    LL a;
    int num;
};
bool vis[maxn];
vector<Node>v[maxn];
vector<Node>bw;
bool cmp(Node a,Node b)
{
    return a.a<b.a;
}
int main()
{
    int n,m,ci;
    LL ans=INF,ai;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld%d",&ai,&ci);
        Node t;
        t.a=ai;t.num=i;
        v[ci].push_back(t);
        bw.push_back(t);
    }
    sort(bw.begin(),bw.end(),cmp);
    for(int i=1;i<=n;i++)sort(v[i].begin(),v[i].end(),cmp);
    for(int i=1;i<=m;i++)
    {
        memset(vis,0,sizeof(vis));
        LL money=0,cnum=0;
        for(int j=1;j<=n;j++)
        {
            int cnt=v[j].size();
            for(int k=0;k<v[j].size() && cnt>=i;k++,cnt--,cnum++)
            {
                money+=v[j][k].a;
                vis[v[j][k].num]=true;
            }
        }
        for(int j=0;j<bw.size() && cnum<i;j++)
        {
            if(!vis[bw[j].num])
            {
                money+=bw[j].a;
                vis[bw[j].num]=true;
                cnum++;
            }
        }
        ans=min(ans,money);
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_39826163/article/details/86774816