USACO22OPEN-Bronze A
前言(Front talk)
网址(Website)
SPOJ: 题目详情 - Alchemy - Super
SPOJ: 题解 - Alchemy - Super
题目(Problem)
输入格式(Input)
输出格式(Output)
样例(Example)
样例输入
5
2 0 0 1 0
3
5 2 3 4
2 1 1
3 1 2
样例输出
1
提示(Notice)
样例解释
在这个例子中,以下是一种最优的转化方式:
- 将一单位金属
转化为金属 。 - 将一单位金属
转化为金属 。 - 将一单位金属
和金属 转化为金属 。
现在
测试点性质
测试点
中,对于 ,一单位金属 可以被转化为一单位金属 ; 测试点
中,每个配方均将一单位的一种金属转化为另一种金属; 测试点
没有额外限制。
题解(Solution)
一秒就想到了二分答案,因为答案有个性质:有解的单调性(就是任何小于答案的值都有解,而任何大于答案的值都无解),因此想到二分答案。
代码(Code)
#include<bits/stdc++.h>
#include<vector>
#include<queue>
#define For(i,l,r) for(int i=l;i<=r;++i)
#define Rof(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
#define P pair<int,int>
#define int unsigned long long
#define Fi first
#define Se second
inline int input(){int x;return cin>>x,x;}
const int inf = 1e6+14;
const int N = 10123;
vector<int>ft[N];
int n,k,a[N],lmt[N];
priority_queue<P> q;
inline bool check(int st,int mid){
For(i,1,n) lmt[i]=0;lmt[n]=mid;
Rof(i,n,1){
if(lmt[i]>a[i] && ft[i].empty()) return false;
if(lmt[i]<=a[i]) continue;
lmt[i]-=a[i];
for(auto y:ft[i]) lmt[y]+=lmt[i];
}return true;
//广搜的方法卡常
// while(q.size()) q.pop();
// q.push({st,mid});
// while(q.size()){
// int x=q.top().Fi,hav=q.top().Se;q.pop();
// if(hav>lmt[x]) hav-=lmt[x],lmt[x]=0;
// else {lmt[x]-=hav;continue;}
// if(ft[x].empty() && hav) return false;
// for(auto y:ft[x]) q.push({y,hav});
// }return true;
}
//inline bool check(int mid){
//
//}
inline int Two_division(){
int l=0,r=inf,mid,res;
while(l<=r){
mid=(l+r)>>1;
if(check(n,mid)) l=mid+1,res=mid;
else r=mid-1;
}return res;
}
inline bool cmp(P a,P b){return a.Fi>b.Fi;}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
string str("alchemy");
freopen((str+".in").c_str(),"r",stdin);
freopen((str+".out").c_str(),"w",stdout);
cin>>n;For(i,1,n) a[i]=input();
cin>>k;For(i,1,k){
int x=input(),m=input();
For(j,1,m){int y=input();ft[x].push_back(y);}
}cout<<Two_division()<<'\n';
return 0;
}
后续(Ending)
hav-=lmt[x],lmt[x]=0;
写成了lmt[x]=0,hav-=lmt[x];
。