http://acm.nefu.edu.cn/JudgeOnline/index.php
A.预测商品
你可以知道一个物品每天的价格波动,这样你就可以在价低时买,在价格高时卖。但是你每天只能交易一个物品,就是说你只能买或者卖或者什么都不做。一共有n天,到第n天结束后,你最多得可以多少钱。
同CF865D,http://codeforces.com/contest/865/problem/D
优先队列
物品买卖的题,碰见一个东西,啥都不说,先预定(预定,但不买)下来(放入优先队列),如果它以后能升值,则刷新这个股票的价值,然后获利,如果不能升值,则最后的时候不计算它;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define inf 0x3f3f3f
using namespace std;
priority_queue <int,vector<int>,greater<int> > q;
int n,m;
int main()
{
cin>>n;
long long ans=0;
for(int i=0;i<n;i++)
{
cin>>m;
q.push(m);
if (q.top()<m)
{
ans+=m-q.top();
q.pop();
q.push(m);
}
}
printf ("%I64d\n",ans);
return 0;
}
B.传说之剑
一名传奇巫师接受了一项任务,要为一把传说之剑附魔。巫师一开始有n点魔法值,他能够吟唱两种附魔咒语。 第一种咒语消耗s1点魔法值,为传说之剑增加v1点攻击力。第二种咒语消耗s2点魔法值,为传说之剑增加v2点攻击力。 只要巫师还有足够的魔法值,他可以重复吟唱任一咒语。 求传说之剑最多有多少附魔攻击力。(所有数据<=2000000000)
如果数据不这么大,就是一道背包裸题。。。
思路:直接暴力枚举会TLE,先计算s1 s2的LCM,分两种情况讨论。
1.n<lcm 直接枚举
2.n>=lcm 先求r=n%lcm,将n分为两部分,n-r和r,第一部分直接计算,第二部分暴力枚举。
注意:枚举时使用s1 s2中较大的进行枚举!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 0x3f3f3f
using namespace std;
typedef long long ll;
ll t,n,s1,v1,s2,v2;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld%lld%lld%lld",&n,&s1,&v1,&s2,&v2);
if (s1<s2)
{
swap(s1,s2);
swap(v1,v2);
}
ll ans=0;
ll lcm=s1/gcd(s1,s2)*s2;
ll mod=n%lcm;
if (n<lcm)
{
ll num=0;
while(num*s1<=n)
{
ans=max(ans,(n-num*s1)/s2*v2+num*v1);
num++;
}
}
else
{
ll tmp=(n-mod)/lcm*max(lcm/s1*v1,lcm/s2*v2);
ll num=0;
ll res=mod;
while(num*s1<=res)
{
ans=max(ans,(res-num*s1)/s2*v2+num*v1);
num++;
}
ans+=tmp;
}
printf ("%lld\n",ans);
}
return 0;
}
C.魔法王国
在遥远的青青草原上,有一座魔法王国,王国里有n个城市,现在魔法王国的国王想要在城市间修一些道路,让这些城市互相连通(任意两个城市间均是可达的),在魔法王国修路当然需要魔法了,现在知道有m条双向道路可以被修建,但是每一条道路都需要一定的魔法值,只有魔法值不小于这个值的魔法师才能修建,而且修建之后这个魔法师的魔法值还会损失一。现在魔法王国的国王想要知道如果他只找一个魔法师来建造道路,那么这个魔法师的魔法值至少为多少呢?(题目数据保证一定可以将所有的城市联通)
最小生成树
修每次路的时候,魔法值会减1,除此之外,就是一道最小生成树裸题嘛,每次判断一下就可以了
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <set>
using namespace std;
#define ll long long
const int inf=0x3f3f3f3f;
struct data
{
int a,b,v;
}w[100001];
bool cmp(data q,data e)
{
return q.v<e.v;
}
bool kkk(int q,int e)
{
return q>e;
}
int pre[10001];
int n,m,t;
int find(int x)
{
if (pre[x]!=x)
{
pre[x]=find(pre[x]);
}
return pre[x];
}
void join(int x,int y)
{
int dx=find(x);
int dy=find(y);
if (dx!=dy)
{
pre[dx]=dy;
}
}
int kk[100001];
int main()
{
scanf("%d",&t);
while (t--)
{
scanf("%d%d",&n,&m);
for (int i=0;i<=n;i++) pre[i]=i;
for (int i=0;i<m;i++)
{
scanf("%d%d%d",&w[i].a,&w[i].b,&w[i].v);
}
sort(w,w+m,cmp);
int k=0;
for (int i=0;i<m;i++)
{
if (find(w[i].a)!=find(w[i].b))
{
kk[k++]=w[i].v;
join(w[i].a,w[i].b);
}
}
sort(kk,kk+k,kkk);
int kkkk=kk[0]-1;
int ans=kk[0];
for(int i=1;i<k;i++)
{
if (kkkk<kk[i])
{
ans+=kk[i]-kkkk;
kkkk=kk[i];
}
kkkk--;
}
printf ("%d\n",ans);
}
return 0;
}
D.东南西北
历史上有八卦阵之说,进入到人很难正确找到出口,有八个门。有个大师想创造一个简单版本的,却遇上一个难题:有东,南,西,北四个门位置,假设目前正在东门,大师想知道走n步回到东门的走法共有多少种。每次处于一个门时,走一步只能到其他三个门,且不能不走,每两个门之间都是互通的。请输出走n步之后回到原地的走法数量,走法数量可能非常大,输出对1000000007 (1e9+7)取余。比如在东门,走2步回到东门有多少种走法:东->北->东,东->南->东,东->西->东共三种走法。
简单dp
画一个简单的图会发现是一个完全三叉树,不用预处理可以过,不超时
二维dp,一维代表步数,二维代表在不在起点
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define ll long long
using namespace std;
const int mod=1e9+7;
ll dp[10000001][2];
int n,m,t;
int main()
{
int n;
while(~scanf("%d",&n))
{
dp[2][0]=3;
dp[2][1]=6;
for(int i=3; i<=n; i++)
{
dp[i][1]=(dp[i-1][1]*2+dp[i-1][0]*3)%mod;//现在一步不在起点可以由前一步不在起点*2和前一步在起点*3得到
dp[i][0]=(dp[i-1][1])%mod;//现在一步在起点由前一步不在起点得到
}
printf ("%lld\n",dp[n][0]);
}
return 0;
}
A题比赛时就在想用dp写,然后学长说数据有问题,就没再看
B题真的当时没思路,数据太大了,看题解之前我也没想到是用lcm做的。。
C题不说了,
D题竟然因为不是多组输入wa了两次。。。。。。