0
点赞
收藏
分享

微信扫一扫

ybtoj 二分集合2

J简文 2022-02-18 阅读 46
c++二分法

目录

T1:喂养宠物

T2:最小时间

T3:攻击法坛

T4:跳石头

T5:飞离地球


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;
}
举报

相关推荐

0 条评论