新生36

礼物,点牛,找朋友,数字游戏,跳棋

礼物:

题目描述

在一个n×n的网格图上,放置着m个礼物,每个礼物有一个价值vi(1≤i≤m),你可以选择一个礼物,然后选择:
(1)取走与它同列的所有礼物,或者(2)取走与它同行的所有礼物
请问所能获取的礼物的最大价值之和是多少?

输入

第一行两个正整数n,m。
之后m行,每行三个整数xi,yi,vi,表示第i个礼物在第xi行,第yi列的格子上(不同礼物可能会在同一个格子),其价值为vi。

输出

一个整数,表示能获取的最大的礼物价值之和。

样例输入 Copy

6 7 
1 3 1 
2 2 2 
2 4 4 
3 3 6 
3 6 3 
5 2 5 
5 4 6

样例输出 Copy

11

提示

样例1解释

选择第5行的任意一个礼物,然后将第5行取完。
【数据范围】
对于40%的数据,1≤n,m≤100
对于70%的数据,1≤n,m≤1000,0<vi≤10000
对于100%的数据,1≤n≤1000,1≤m≤105,1≤xi,yi≤n,vi≤106
这题数据范围很大要注意开longlongint
然后有一句话很关键!!不同礼物可能会在同一个格子
单纯的覆盖会把之前的礼物价值覆盖掉,得加上才行
复制代码
#include<iostream>
using namespace std;
int a[5000][5000];
int main(){
    long long int n,m,x,y,v,maxn=-1;
    scanf("%lld%lld",&n,&m);
    for(int i=0;i<m;i++)
    {
        scanf("%lld%lld%lld",&x,&y,&v);
        if(a[x][y])
            a[x][y]+=v;
        else
            a[x][y]=v;
    }
    for(int i=1;i<=n;i++)
    {
        long long int sum=0;
        for(int j=1;j<=n;j++)
        {
            sum=sum+a[i][j];
            maxn=max(maxn,sum);
        }
    }
    for(int j=1;j<=n;j++)
    {
        long long int ans=0;
        for(int i=1;i<=n;i++)
        {
            ans=ans+a[i][j];
            maxn=max(maxn,ans);
        }
    }
    cout<<maxn<<endl;
    return 0;
} 
复制代码

点牛:

在农夫FJ(Farmar John)的农场中有成千上万头奶牛,庞大的牛群给FJ增添了很多麻烦,尽管他为每一头奶牛从1开始顺序编上了号码,但是在每天清晨点名时(确切的说是点牛),FJ还是常常被巨大的数字弄得头晕,比如: 
FJ:奶牛一亿两千三百四十五万九千九百九十九号! 
Cow 123459999:到! 
FJ:奶牛一亿两千三百四十……??? ……!@#$!@#$ 
你能帮助FJ解决这个问题吗?你只需要写一个程序,当FJ点到一头奶牛时,及时提醒他下一头奶牛的编号就可以了。^_^ 

 

输入

仅有一个整数:即FJ刚刚点过的奶牛的编号N。1 ≤ N ≤ 1050

输出

快告诉FJ下一头奶牛的编号吧!

样例输入 Copy

3

样例输出 Copy

4
这题没啥好说的,高精度,简单的说高精加1
写的又臭又长...
复制代码
#include<iostream> 
#include<cstring>
using namespace std;
int main(){
    char ch1[1100],ch2='1';
    int la,lb,lc,i,a[1100],b[1100],c[1100];
    cin>>ch1;
    la=strlen(ch1);
    lb=1;
    lc=la>lb?la:lb;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(i=0;i<la;i++)
    {
        a[la-i-1]=ch1[i]-'0';
    }
    for(i=0;i<lb;i++)
    {
        b[lb-i-1]=ch2-'0';
    }
    memset(c,0,sizeof(c));
    for(i=0;i<lc;i++)
    {
        c[i]=a[i]+b[i]+c[i];
        if(c[i]>=10)
        {
            c[i+1]=1;
            c[i]-=10;
        }
    }
    if(c[lc]>0)
    {
        lc++;
    }
    for(i=lc-1;i>=0;i--)
    {
        cout<<c[i];
    }
    return 0;
}
复制代码

这是一位大佬的代码:

复制代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char c[100];
int a[100],len;
void jw(int i){        
    if(i>len) len=i;
    a[i]++;
    if(a[i]==10) {
        a[i]=0; jw(i+1);
    }
    return;
}
int main(){
    scanf("%s",&c);
    len=strlen(c);
    for(int i=0;i<strlen(c);i++) a[i+1]=c[strlen(c)-i-1]-'0'; 
    jw(1);               
    for(int i=len;i>=1;i--) cout<<a[i];
}
复制代码

********************************************************************

 找朋友:

问题 E: 朋友
题目描述
经过六年的努力,小明终于被一所知名中学录取。优秀的小明总是对一些奇奇怪怪的事情感兴趣,这次他想知道谁在这所新学校拥有的朋友最多,由于大家都才刚报到,所以小明只知道大家两两之间是否是朋友关系。

输入
的第一行有两个整数n和m,n表示总人数,m表示总关系数。
接下来n行,每行有2个以空格隔开的整数a和b,表示a和b是朋友,a和b均为1到n之间的整数。不会给出重复的朋友关系。
输出
仅有一行,表示朋友数最多的人所拥有的朋友,每两个整数之间用空格隔开,按照字典序从小到大输出。如果存在多个人朋友数都是最多的情况,请输出字典序最小的那人的答案,具体见样例。
样例输入 Copy
3 3
1 2
2 3
1 3
样例输出 Copy
2 3
 这个题第一反应就是二维数组,但你得用STL的板子,不然数组开的不够大,但我写的还是很艰难:

复制代码
#include<iostream>
#include<algorithm> 
#include<vector>
using namespace std;
typedef pair<int,int> PAII;
const int N=1e6+10;
vector<int> g[N];//这个是开二维数组,一维的大小确定是N,二维不确定
PAII p[N];
int cmp(PAII x,PAII y)
{
    if(x.first==y.first)
        return x.second<y.second;
    else
        return x.first>y.first;
}
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        cin>>x>>y;
        g[x].push_back(y);//把每一个人的好朋友都记录下来,一行表示好朋友,列代表一共有这么多的人 
        g[y].push_back(x);
    }
    for(int i=1;i<=n;i++)
        p[i]={g[i].size(),i};//编号和个数进行捆绑,下面好对个数进行排序
    sort(p+1,p+n,cmp);//对个数进行排序,大的在前面 
    sort(g[p[1].second].begin(),g[p[1].second].end());//对要输出朋友的那一行继续字典序排序
    for(auto item:g[p[1].second])//遍历g[1]进行输出 
        cout<<item<<" ";
    return 0;
}
复制代码

 数字游戏;

题目描述

有一天,小明给佳佳出了一道题,
给出一个正整数n,佳佳可以进行如下三种操作:
1、使n减去1
2、如果n是2的倍数,使n除以2
3、如果n是3的倍数,使n除以3
问佳佳最少可以通过几步操作,将n变为0。
为了考验佳佳的知识水平,小明给出了T个数字n1,n2,…,nT,让佳佳对每个数字都给出答案。然而佳佳一心只想着晚上吃啥,想让聪明的你来帮助他解决这个问题,并答应解决后请你吃饭,于是你义不容辞地接下了这个任务。

输入

第一行一个正整数T,表示总共有T个数字;
接下来T行,每行一个正整数ni

输出

共T行,每行一个数字,第i行为对于ni的答案。

样例输入 Copy

2 
7 
10

样例输出 Copy

4
4

提示

【样例解释】
7->6->2->1->0
10->9->3->1->0

【数据范围】
对于40%的数据,T≤10,ni≤30
对于70%的数据,T≤20,ni≤1000
对于100%的数据,T≤20,ni≤1000000
这题用动态规划来做,我找到很好描述动态规划的那个小故事了
****************************************************************

A * "1+1+1+1+1+1+1+1 =?" *

A : "上面等式的值是多少"
B : *计算* "8!"

A *在上面等式的左边写上 "1+" *
A : "此时等式的值为多少"
B : *quickly* "9!"
A : "你怎么这么快就知道答案了"
A : "只要在8的基础上加1就行了"
A : "所以你不用重新计算因为你记住了第一个等式的值为8!动态规划算法也可以说是 '记住求过的解来节省时间'"

******************************************************************

这个题用动态规划,把每一种情况用数组存起来,最后直接输出dp[n];

具体的规划过程:

一个数i可以由i-1得到,如果可以被3或者2整除,那就可以由i/3或者i/2得到,记住得到的时候步数的加一步要算上

然后选哪一个步骤呢?那就取这两步的最小值就好了

复制代码
#include<iostream>
using namespace std; 
const int N=1e6+7;
int dp[N+11];
void solve(){
    dp[0]=1;
    dp[1]=1;//初始化
    for(int i=2;i<=N;i++)
    {
        dp[i]=dp[i-1]+1;//i可以由i-1得到
        if(i%3==0) dp[i]=min(dp[i],dp[i/3]+1);//如果选择从i/3的位置到i那就是再加1,不选择这么做那就是dp[i],取最小值 
        if(i%2==0) dp[i]=min(dp[i],dp[i/2]+1); 
    }
}
int main(){
    int n;
    cin>>n;
    solve();
    while(n--)
    {
        int x;
        cin>>x;
        cout<<dp[x]<<endl;//n的时候可以有多少步 
    }
    return 0;
} 
复制代码

 跳棋:

题目描述

小明迷恋上了一个新的跳棋游戏,游戏规则如下:棋盘是一排从0开始,顺序编号的格子,游戏开始时你位于0号格子,你每次只能往编号大的格子跳,而且你每次至少需要跳过L个格子,至多只能跳过R个格子。每个格子都有一个给定的伤害值,显然你希望得到的伤害值越少越好。 
你能告诉小明他当他跳到最后一个格子时受到的累积伤害值最小为多少吗? 
  如果无论如何小明都无法跳到最后一个格子,这个时候你需要输出”-1”。 
注:从i号格子跳过x个格子表示从i号格子跳到第i+x+1号格子。 

输入

第一行有三个整数n、L和R,n表示格子的编号从0到n。L和R表示最少需要跳过的格子数和最多能够跳过的格子数。 
第二行有n个正整数,两个数字间用空格隔开,表示每个格子的伤害值。 

输出

仅有一个整数,表示受到的最小伤害值,保证结果小于max long int。

样例输入 Copy

10 2 6 
1 3 5 7 9 2 4 6 8 10

样例输出 Copy

12

提示


50%的数据,1<=n<=1000
65%的数据,1<=n<=10000
100%的数据,1<=n<=1000000,1<=L<=R<=n
其中有15%的数据,1<=n<=1000000,1<=L<=R<=10
这题显而易见用动态规划做
状态转移方程是令f[i]为跳到第i个格时的最小伤害值
f[i]=min[f[j]+a[i]](j的范围根据i来定),这题的细节相当细,慢慢的,慢慢的...
不过这样做双重枚举,时间复杂度是O(n*n),必超时,得优化
想到了单调队列,dp维护单调队列:
还记得滑动窗口吗?单调队列的本质就是求一段定区间的最值(且复杂度为O(n)),刚刚的状态转移方程中f[j]也就是上一个区间的最值加上a[j]罢了
但逐步递推,很容易想到这个方法啊
废物是我了吧,知道思路看不懂代码,nnd....有几处代码理解的有点问题,先放上来,后期再看QAQ
复制代码
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e6+10;
long int q[N],hh=1,tt,dp[N],a[N];
int main(){
    int n,l,r;
    cin>>n>>l>>r;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    memset(dp,-1,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=n;i++)
    {
        while(hh<=tt&&q[hh]<i-r-1) hh++;
        if(i-l-1>=0&&dp[i-l-1]!=-1)//
        {
            while(hh<=tt&&dp[q[tt]]>=dp[i-l-1]) tt--;
            q[++tt]=i-l-1;
        }
        if(hh<=tt) dp[i]=dp[q[hh]]+a[i];
    }
    cout<<dp[n]<<endl;
    return 0;
}
复制代码

**********************打个码吧....提醒自己...

 

posted @   小志61314  阅读(92)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示