9.12题解
不算很难,但环境问题卡死一堆人。
T1
众所周知,一场比赛需要一道签到题。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string s;
int main()
{
cin >> s;
cout << count(s.begin(), s.end(), '1');
return 0;
}
T2
我们考虑选优惠券时要考虑的参数:
- 是否过期
- 价格可用
- 没有用过
很明显,1 的判断对程序效率影响最大。
我们发现,如果某一张优惠券在某一时刻过期了,
那么在这之后它也一定是过期的。
所以如果我们发现了一张过期优惠券,那它肯定没用了,扔掉就行了。
然后要用优惠券的时候,因为过期的都扔掉了,就不需要重复判断它们。
这题用链表是最好的,但用队列足够了。
把优惠券依次压到队里,每到下一个时刻就把过期的弹出去。
#include <iostream>
#include <utility>
using namespace std;
int h, t, n;bool vis[100050];pair<int, int> a[100050];long long ans;
int main()
{
cin >> n;
for(int i = 0, p, q, f;i < n;++i)
{
cin >> f >> p >> q;
while(h < t && a[h].second < q) ++h;
if(f)
{
bool flag = 0;
for(int j = h;j < t;++j)
if(!vis[j] && a[j].first >= p)
{
vis[j] = 1;flag = 1;break;
}
if(!flag) ans += p;
}
else a[t++] = make_pair(p, q + 45), ans += p;
}
cout << ans;
return 0;
}
T3
几乎是裸的完全背包虽然我考场上没想出来,只是建模会有些难。
我们先想一想,一个纪念品,是通过什么赚钱的?
答:从一个低价买入,然后在某个高价时卖出,赚中间的差价。
那么光是这样是写不了 dp 的,因为无法判断要从哪个低价转移到高价。
那如果买了一个东西,第二天马上卖掉呢?
这样是不会影响结果的,因为第二天卖掉之后可以立刻买回来。
然后在第三天再全卖掉,买新的,以此类推……
然后我们就可以开始构造背包模型了。
很明显,背包容量=当前手上剩下的钱。
重量=纪念品当天的价格。
那价值怎么算呢?我们先看看钱是怎么赚的。
上面说了,钱是差价赚出来的。
所以价值=纪念品下一天的价格 - 纪念品当天的价格。
有人就会担心了:如果差价是负的咋办?
凉拌。要是负的背包根本不会考虑它。
为了让代码看着简单点,我用宏定义来表示这几个值:
#include <iostream>
#include <cstring>
#define w(i) p[k][i]
#define v(i) p[k + 1][i] - p[k][i]
using namespace std;
int t, n, m, p[150][150], dp[100050];
int main()
{
cin >> t >> n >> m;
for(int i = 1;i <= t;++i)
for(int j = 1;j <= n;++j)
cin >> p[i][j];
for(int k = 1;k < t;++k)
{
memset(dp, 0, sizeof dp);
for(int i = 1;i <= n;++i)
for(int j = w(i);j <= m;++j)
dp[j] = max(dp[j], dp[j - w(i)] + v(i));
m += dp[m];
}
cout << m;
return 0;
}
T4
最短路,奇偶性。虽然我考场上也没想出来
我们知道,题目大意就是给定 $q$ 组 $a$ 和 $l$,
让你判断从 $a$ 开始走 $l$ 步能不能到 $1$。
那么,如果走 $l$ 步能到,那么走 $l+2$ 步肯定也能到(中间徘徊一下)
同理,走 $l+4,l+6……l+2^k$ 肯定都能到。
那么我们可以说:
走 ($≥l$ 且与 $l$ 奇偶性相等) 步肯定能到。
所以,我们要让 $l$ 尽可能小。
然后就是最短路了,只不过要分别求奇数偶数,用冰法师方便一些。
注意奇数下一步是偶数,偶数下一步是奇数。
#include <iostream>
#include <queue>
#include <list>
#include <cstring>
#include <utility>
using namespace std;
list<int> edge[100050];int n, m, t, dis0[100050], dis1[100050];
void add(int u, int v) {edge[u].push_back(v);}
void bfs()
{
queue<pair<int, int> > q;
for(auto &v : edge[1])
dis1[v] = 1, q.push(make_pair(v, 1));
while(!q.empty())
{
int u = q.front().first, dep = q.front().second;q.pop();
for(auto &v : edge[u])
if(dep % 2) //奇数
{
if(dis0[v] > dep + 1) //奇数下一步是偶数
{
dis0[v] = dep + 1;
q.push(make_pair(v, dis0[v]));
}
}
else //偶数
{
if(dis1[v] > dep + 1) //偶数下一步是奇数
{
dis1[v] = dep + 1;
q.push(make_pair(v, dis1[v]));
}
}
}
}
int main()
{
cin >> n >> m >> t;
for(int i = 0, u, v;i < m;++i)
cin >> u >> v, add(u, v), add(v, u);
memset(dis0, 0x3f, sizeof dis0);dis0[1] = 0;
memset(dis1, 0x3f, sizeof dis1);bfs();
for(int i = 0, a, l;i < t;++i)
{
cin >> a >> l;
if(l % 2)
{
if(l < dis1[a]) cout << "No" << endl;
else cout << "Yes" << endl;
}
else
{
if(l < dis0[a]) cout << "No" << endl;
else cout << "Yes" << endl;
}
}
return 0;
}