目录
T1:喂养宠物
然而此时我只想吃麻辣兔头。。。结构体内的比 cmp 要快一些,< 从小到大,> 从大到小。养一个兔子的代价相当于自己吃的加上使别人多吃的粮食,应二分兔子个数,在此基础上贪心
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=55;
int n,tot;
struct rabbit{
int hunger,greed,cost;
bool operator < (const rabbit &G) const
{
return cost<G.cost;
}
}a[N];
bool check(int x)
{
for(int i=1;i<=n;i++) a[i].cost=a[i].hunger+(x-1)*a[i].greed;
sort(a+1,a+n+1);
int res=0;
for(int i=1;i<=x;i++) res+=a[i].cost;
return res>tot;
}
int main()
{
scanf("%d%d",&n,&tot);
for(int i=1;i<=n;i++) scanf("%d",&a[i].hunger);
for(int i=1;i<=n;i++) scanf("%d",&a[i].greed);
int l=0,r=n;
while(l<r)
{
int mid=l+r+1>>1;
if(check(mid)) r=mid-1;
else l=mid;
}
cout<<l;
return 0;
}
T2:最小时间
显然二分时间这种类似于坐标轴的东西,注意 check 的时候物品价值不应纠结于各元素在每一事件的价值,而是统计每一物品在该时间的价值。由于只能选 m 个,故只需找出最大的 m 个
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
long long n,m,s;
long long val[N],k[N],b[N];
bool check(int x)
{
for(int i=1;i<=n;i++) val[i]=k[i]*x+b[i];
nth_element(val+1,val+m,val+n+1,greater<long long>());
/*
函数只是把下标为k的元素放在了正确位置,对其它元素并没有排序
当然k左边元素都小于等于它,右边元素都大于等于它
nth_element(begin,nth,end,cmp);
*/
long long sum=0;
for(int i=1;i<=m;i++)
{
if(val[i]>0&&(sum+=val[i])>=s) return 1;
}
return sum>=s;
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&s);
for(int i=1;i<=n;i++) scanf("%lld%lld",&k[i],&b[i]);
if(check(0))
{
printf("0");
return 0;
}
int l=1,r=1e9;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%d",l);
return 0;
}
T3:攻击法坛
什么玩意儿一沾上 DP 就不可爱了,尤其是本来就丑的一批的二分。另外书上有问题:check 中返回dp [ p ] [ q ] 应为 dp [ R ] [ G ] 。用两个数组表示在某位置用 1 , 2 号魔法棒可覆盖多远,DP 二位数组表示第 i 次用 1 ,第 j 次用 2 能覆盖多远。二分答案 L 。
#include<bits/stdc++.h>
using namespace std;
int n,R,g;
int a[2010],f1[2010],f2[2010],dp[2010][2010];
int main()
{
cin>>n>>R>>g;
for (int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
int l=1,r=a[n]+a[1]+1,mid;
while(l<r)
{
mid=(l+r)>>1;
memset(f1,0,sizeof(f1));
memset(f2,0,sizeof(f2));
memset(dp,0,sizeof(dp));
for (int i=1;i<=n;i++)
{
for (int j=i;j<=n;j++)
{
if(a[i]+mid>a[j]) f1[i]=j;
if(a[i]+mid*2>a[j])f2[i]=j;
}
}
for (int i=0;i<=R;i++)
{
for (int j=0;j<=g;j++)
{
if(i>0)dp[i][j]=max(dp[i][j],f1[dp[i-1][j]+1]);
if(j>0)dp[i][j]=max(dp[i][j],f2[dp[i][j-1]+1]);
if(dp[i][j]>=n)
{
r=mid;
goto next;
}
}
}
if(dp[R][g]>=n)r=mid;
else l=mid+1;
next: ;
}
cout<<l;
return 0;
}
T4:跳石头
对d进行二分,判断最小距离为d时移走的最少石头数是否会超过M块,详见洛谷团队寒假作业2.9
T5:飞离地球
太虐了!!!我从9:30申请完博客搬家开始,直至下午3:00几乎一直在弄他(我好菜QwQ)鉴于学习 SPFA 时没有及时 belog,负环怎么判我简直忘得一干二净。。。但效果还好,80—>80———>80—>0—>100,一开始我是有负环就直接判无法到达了,后来对着标程找不同(仿佛找了一整年),完全改不过来(因为我压根不知道书在说什么,我写的和书给的仿佛毫不相干)。最后我放弃了,完全照书写,改了完全看不懂的 SPFA ,终于过了
#include <bits/stdc++.h>
using namespace std;
const int inf = 2147483647;
int u, v, w, h[110], T, n, m, cnt, mid, dis[110], ans;
bool mark[110], vis[110], con[110];
struct edge {
int t, n, d;
} e[2000010];
void add(int u, int v, int w) {
e[++cnt].n = h[u];
e[cnt].t = v;
e[cnt].d = w;
h[u] = cnt;
}
void dfscon(int x) {
mark[x] = 1;
for (int i = h[x]; i; i = e[i].n) if (!mark[e[i].t]) dfscon(e[i].t);
}
inline bool dfs(int x) {
mark[x] = 1;
for (int i = h[x]; i; i = e[i].n)
if (dis[e[i].t] > dis[x] + e[i].d + mid && con[e[i].t]) {
if (mark[e[i].t]) return 1;
dis[e[i].t] = dis[x] + e[i].d + mid;
if (dfs(e[i].t)) return 1;
}
mark[x] = 0;
return 0;
}
void spfa() {
for (int i = 1; i <= n; i++) dis[i] = inf;
memset(vis, 0, sizeof(vis));
dis[1] = 0, vis[1] = 1;
queue<int> q;
q.push(1);
while (!q.empty()) {
int u = q.front();
vis[u] = 0;
q.pop();
for (int i = h[u]; i; i = e[i].n) {
int v = e[i].t;
if (dis[v] > dis[u] + e[i].d + mid && con[v]) {
dis[v] = dis[u] + e[i].d + mid;
if (!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
}
}
bool judge() {
for (int i = 1; i <= n; i++)
if (con[i]) {
memset(dis, 0, sizeof(dis));
memset(mark, 0, sizeof(mark));
if (dfs(i)) return 0;
}
spfa();
if (dis[n] >= 0 && dis[n] != inf) return 1;
return 0;
}
int main() {
scanf("%d",&T);
while (T--) {
memset(con, 1, sizeof(con));
memset(h, 0, sizeof(h));
memset(mark, 0, sizeof(mark));
cnt = 0, ans = -1;
scanf("%d%d",&n,&m);
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u, v, w);
}
dfscon(1);
for (int i = 1; i <= n; i++) if (!mark[i]) con[i] = 0;
for (int i = 1; i <= n; i++)
if (con[i]) {
memset(mark, 0, sizeof(mark));
dfscon(i);
if (!mark[n]) con[i] = 0;
}
int l = -1e6, r = 1e6;
while (l < r) {
mid = (l + r) >> 1;
if (judge()) ans = dis[n], r = mid;
else l = mid + 1;
}
printf("%d\n", ans);
}
return 0;
}