8.15 Test Problem Solution.

5 篇文章 0 订阅
5 篇文章 0 订阅

1.第K小数(number.cpp/c/pas)

题目描述

有两个正整数数列,元素个数分别为N和M。从两个数列中分别任取一个数

相乘,这样一共可以得到N*M个数,询问这N*M个数中第K小数是多少。

输入输出格式

输入格式:

输入文件名为number.in。

输入文件包含三行。

第一行为三个正整数N,M和K。

第二行为N个正整数,表示第一个数列。

第三行为M个正整数,表述第二个数列。

输出格式:

 输出文件名为number.out。

输出文件包括一行,一个正整数表示第k小数。

输入输出样例

输入样例#1:
2 3 4
1 2
2 1 3
输出样例#1:
3
输入样例#2:
5 5 18
7 2 3 5 8
3 1 3 2 5
输出样例#2:
16

说明

1<=n,m<=200000,1<=k<=20000010000,数列元素<=10^9;

 

test的时候好不容易想到了二分,结果犯了几个sb错误,sort写错了,Judge函数参数传错了,还好没有爆零得了25分,GG。

两个数列(a,b)sort之后,a[i]*b[1-m]是满足单调性的,b[i]*a[1-n]也是满足单调性的,所以可以二分。

25分BUG-Code:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 200010
#define maxm 200010
ll a[maxn],b[maxm],k;
int n,m;
inline void input(ll &x) {
    x=0;
    ll a=1;char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    return;
}
inline void read(int &x) {
    x=0;
    int a=1;char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    return;
}
inline bool judge(int x) {
    ll rank=0;
    for(int i=1,j=m;i<=n;++i,rank+=(ll)j)
        while(j>=1&&a[i]*b[j]>x) j--;
    return rank<k?false:true;
}
int main() {
    read(n),read(m),input(k);
    for(int i=1;i<=n;++i) input(a[i]);
    for(int i=1;i<=m;++i) input(b[i]);
    sort(a+1,a+n+1);
    sort(b+1,b+n+1);
    ll l=0,r=a[n]*b[m],mid,ans;
    while(l<=r) {
        mid=l+r>>1;
        if(judge(mid)) {
            r=mid-1;
            ans=mid;
        } else l=mid+1;
    }
    cout<<ans;
    return 0;
}

  Judge参数改为ll,sort b数组改为b+m+1就可以A,mdzz;

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 200010
#define maxm 200010
ll a[maxn],b[maxm],k;
int n,m;
inline void input(ll &x) {
    x=0;
    ll a=1;char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    return;
}
inline void read(int &x) {
    x=0;
    int a=1;char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    return;
}
inline bool judge(ll x) {
    ll rank=0,j=m;
    for(int i=1;i<=n;++i,rank+=j)
        while(j>=1&&a[i]*b[j]>x) j--;
    return rank<k?false:true;
}
int main() {
    read(n),read(m),input(k);
    for(int i=1;i<=n;++i) input(a[i]);
    for(int i=1;i<=m;++i) input(b[i]);
    sort(a+1,a+n+1);
    sort(b+1,b+m+1);
    ll l=0,r=a[n]*b[m],mid,ans;
    while(l<=r) {
        mid=l+r>>1;
        if(judge(mid)) {
            r=mid-1;
            ans=mid;
        } else l=mid+1;
    }
    cout<<ans;
    return 0;
}

2.dwarf tower(dwarf.cpp/c/pas)

题目描述

Vasya在玩一个叫做"Dwarf Tower"的游戏,这个游戏中有n个不同的物品,

它们的编号为1到n。现在Vasya想得到编号为1的物品。

获得一个物品有两种方式:

  1. 直接购买该物品,第i件物品花费的钱为ci

  2. 用两件其他物品合成所需的物品,一共有m种合成方式。

请帮助Vasya用最少的钱获得编号为1的物品。

输入输出格式

输入格式:

 

第一行有两个整数n,m(1<=n<=10000,0<=m<=100000),分别表示有n种物品以

及m种合成方式。

接下来一行有n个整数,第i个整数ci表示第i个物品的购买价格,其中

0<=ci<=10^9。

接下来m行,每行3个整数ai,xi,yi,表示用物品xi和yi可以合成物品ai,其

中(1<=ai,xi,yi<=n; ai<>xi, xi<>yi, yi<>ai)

 

输出格式:

 

一行,一个整数表示获取物品 1 的最少花费。

 

输入输出样例

输入样例#1:
5 3
5 0 1 2 5
5 2 3
4 2 3
1 4 5
输出样例#1:
2

说明

60%的数据,n<=100

100%的数据,n<=10000,m<=100000

 

T2一看上去就比较简单,自己手画了一下,感觉可以直接可以边读入边更新,最后输出w[1]就好了。不过很快我就发现了这个算法的缺陷,如果一个物品A能通过合成两个物品来减小费用,那么以前这个A更新过的费用就不是最小的,GG。苦思冥想最后想出来了一种类似于spfa的bfs的做法,开一个struct,记录x和y可以合成a,还有就是类似于存边的next和head,一开始先把所有物品push进队列里,确保每个物品都会更新,其余的就是类似于spfa的操作,这貌似是正解,本来可以A,可惜我TM入队入错了GG,还好数据水,得了40分。

40分BUG-Code

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 10010
#define maxm 100010
struct woyaoac {//忽略掉这个结构体名
    int x,y,a,next;
    woyaoac(int x=0,int y=0,int a=0,int next=0):
        x(x),y(y),a(a),next(next) {}
}A[maxm<<1];
int cnt,w[maxn],head[maxn],n,m;
bool notinq[maxn]={0};
queue<int>q;
inline int input() {
    int x=0,a=1;char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    return x*a;
}
inline void add(int x,int y,int a) {
    A[++cnt]=woyaoac(x,y,a,head[x]);
    head[x]=cnt;
    return;
}
int lpfa() {//忽略掉这个函数名
    for(int i=1;i<=n;i++) q.push(i);
    while(!q.empty()) {
        int x=q.front();
        q.pop();
        notinq[x]=true;
        for(int i=head[x];i;i=A[i].next) {
            int y=A[i].y,a=A[i].a;
            if(w[x]+w[y]<w[a]) {
                w[a]=w[x]+w[y];
                if(notinq[y]==true) {
                    q.push(y);
                    notinq[y]=false;
                }
            }
        }
    }
    return w[1];
}
int main() {
    n=input(),m=input();
    for(int i=1;i<=n;i++) w[i]=input();
    for(int i=1;i<=m;i++) {
        int a=input(),x=input(),y=input();
        add(x,y,a);
        add(y,x,a);
    }
    printf("%d",lpfa());
    return 0;
}

看到那个if(notinq[])了吗?把y改成a就A了,GG。

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 10010
#define maxm 100010
struct woyaoac {
    int x,y,a,next;
    woyaoac(int x=0,int y=0,int a=0,int next=0):
        x(x),y(y),a(a),next(next) {}
}A[maxm<<1];
int cnt,w[maxn],head[maxn],n,m;
bool notinq[maxn]={0};
queue<int>q;
inline int input() {
    int x=0,a=1;char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    return x*a;
}
inline void add(int x,int y,int a) {
    A[++cnt]=woyaoac(x,y,a,head[x]);
    head[x]=cnt;
    return;
}
int lpfa() {
    for(int i=1;i<=n;i++) q.push(i);
    while(!q.empty()) {
        int x=q.front();
        q.pop();
        notinq[x]=true;
        for(int i=head[x];i;i=A[i].next) {
            int y=A[i].y,a=A[i].a;
            if(w[x]+w[y]<w[a]) {
                w[a]=w[x]+w[y];
                if(notinq[a]==true) {
                    q.push(a);
                    notinq[a]=false;
                }
            }
        }
    }
    return w[1];
}
int main() {
    n=input(),m=input();
    for(int i=1;i<=n;i++) w[i]=input();
    for(int i=1;i<=m;i++) {
        int a=input(),x=input(),y=input();
        add(x,y,a);
        add(y,x,a);
    }
    printf("%d",lpfa());
    return 0;
}

3.abcd(abcd.cpp/c/pas)

题目描述

有4个长度为N的数组a,b,c,d。现在需要你选择N个数构成数组e,数组e满足

a[i]≤e[i]≤b[i]以及

并且使得最大。

输入输出格式

输入格式:

 

输入文件名为abcd.in。

输入文件共 N+1 行。

第 1 行包含1个正整数N。

第 i+1 行包含4个整数a[i],b[i],c[i],d[i]。

 

输出格式:

 

输出文件名为abcd.out。

 

输出文件共 1 行,包含1个正整数表示所给公式的最大值,输入保证一定有解。

 

输入输出样例

输入样例#1:
10
1 10 1 0
-10 10 2 2
-10 10 2 2
-10 10 2 2
1 10 1 0
-10 10 2 2
-10 10 2 2
1 10 1 0
-10 10 2 2
1 10 1 0
输出样例#1:
-4

说明

对于 20%的数据,N≤10,-2≤a[i]<b[i]≤2;

对于 60%的数据,N≤50, -20≤a[i]<b[i]≤20;

对于 100%的数据,

N≤200,-25≤a[i]<b[i]≤25,1≤c[i]≤20,0≤d[i] ≤10000

 

 人生第一道玄学DFS+卡时。稳稳当当的20分。

 或许你可以学到卡时QAQ

#include<ctime> 
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 210
#define inf 0x7fffffff
int a[maxn],b[maxn],c[maxn],d[maxn];
int e[maxn],Ans=-inf,n,T;
inline int input() {
	int x=0,a=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())
		if(c=='-') a=-1;
	for(;c>='0'&&c<='9';c=getchar())
		x=x*10+c-'0';
	return x*a;
}
void dfs(int x,int ans) {
	if(clock()-T>=900) {
		printf("%d",Ans);
		exit(0);
	}
	if(x==n+1) {
		int sum=0;
		for(int i=1;i<=n;i++) sum+=e[i]*c[i];
		if(sum==0) Ans=max(Ans,ans);
		else return;
	} else for(int i=a[x];i<=b[x];i++) {
		int t=e[x];
		e[x]=i;
		dfs(x+1,ans+e[x]*d[x]);
		e[x]=t;
	}
	return;
}
int main() {
	T=clock();
	n=input();
	for(int i=1;i<=n;i++)
		a[i]=input(),b[i]=input(),c[i]=input(),d[i]=input();	
	dfs(1,0);
	printf("%d",Ans);
	return 0;
}

正解是多重背包。GG。

∑e[i]*c[i]=0 和 ans=∑b[i]*e[i]
因为e[i]=[a[i],b[i]]等价于[0,b[i]-a[i]]+a[i];
问题转化为使得 ∑(b[i]-a[i])*c[i]+∑a[i]*c[i]=0 且∑(b[i]-a[i])*d[i]+∑a[i]*d[i]最大.
∑a[i]*c[i]和∑a[i]*d[i]是可以计算的.
令V=∑a[i]*c[i](V<0),s[i]=b[i]-a[i].
问题转化为在体积为-V的背包中取物品s[i]求最大值. 可以二进制拆01背包.GG

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 210
#define maxm 100010
int a[maxn],b[maxn],c[maxn],d[maxn];
int dp[maxm],w[maxm],v[maxm];
int ans,V,cnt;
inline int input() {
    int x=0,a=1;char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    return x*a;
}
int main() {
    int n=input();
    for(int i=1;i<=n;i++) {
        a[i]=input(),b[i]=input(),c[i]=input(),d[i]=input();
        V+=a[i]*c[i];
        b[i]-=a[i];
        ans+=a[i]*d[i];
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=b[i];j<<=1) {
            b[i]-=j;
            w[++cnt]=d[i]*j;
            v[cnt]=c[i]*j;
        }
        if(b[i]) {
            w[++cnt]=d[i]*b[i];
            v[cnt]=c[i]*b[i];
        }
    }
    memset(dp,-127/3,sizeof(dp));//神TM的127
    dp[0]=0,V*=-1;
    for(int i=1;i<=cnt;i++)
        for(int j=V;j>=v[i];j--)
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
    ans+=dp[V];
    printf("%d",ans);
    return 0;
}

  

本来是100+100+20=220,结果最后25+40+20=GG。

神TM的sort,神TM的lpfa.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值