2018.8.7提高B组模拟考试
T1 题意简述:jzoj5461
解题思路:贪心。
考虑先用完k张优惠券,只需将商品按优惠价排序,依次判断钱是否足够,若是则ans++,否
则直接退出循环并输出ans即可。
k张优惠券用完后若钱还未用完,则考虑用前面商品的优惠券买后面的商品。注意要把未买
的商品按原价重新排序。只需把用了优惠券的商品的原价与优惠价之差价放进一个小根堆,
每次判断:此商品原价是否小于堆顶商品差价+此商品优惠价。若是则直接用原价买即可,
否则用堆顶商品差价+此商品优惠价买即可。
注意有0张优惠券的情况,因此要特判队列是否为空,若是则直接用原价买即可。
由于本蒟蒻及ErkkiErkko均认为把商品按原价重新排序的方法有误,故欢迎大佬Hack。
8.11 fix:
Zinn大佬已Hack掉以上算法。具体数据请看讨论。
附上sdfzsyq大佬的正确代码:
https://blog.csdn.net/qq_40448823/article/details/81488195
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #include<vector> #define INF 0x3f3f3f3f #define ll long long using namespace std; ll n,k,m,ans; priority_queue<ll,vector<ll>,greater<ll> > que; struct uio{ ll val,fre; }war[50001]; bool cmp(uio x,uio y) { if(x.fre==y.fre) return x.val<y.val; return x.fre<y.fre; } bool cmp1(uio x,uio y) { return x.val<y.val; } int main() { freopen("shopping.in","r",stdin); freopen("shopping.out","w",stdout); scanf("%lld%lld%lld",&n,&k,&m); for(ll i=1;i<=n;i++) scanf("%lld%lld",&war[i].val,&war[i].fre); sort(war+1,war+1+n,cmp); for(ll i=1;i<=k;i++) { que.push(war[i].val-war[i].fre); if(m>=war[i].fre) m-=war[i].fre,ans++; } sort(war+1+k,war+1+n,cmp1); for(ll i=k+1;i<=n;i++) { if(m>=war[i].val&&(que.empty()||que.top()>war[i].val-war[i].fre)) m-=war[i].val,ans++; else if(!que.empty()&&m>=war[i].fre+que.top()) m-=war[i].fre+que.top(),ans++,que.pop(),que.push(war[i].val-war[i].fre); } printf("%lld\n",ans); return 0; }
T2 题意简述:jzoj5455
解题思路:乍一看是一道树形dp...然而现实狠狠地打了你的脸...
这道题的难度远不及树形dp...只需要分两步:
1.计算出有多少对企鹅能只用一根网线相连
2.若还有企鹅没有连接就每只企鹅分配一根网线
就完了...
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define ll long long using namespace std; ll T,n,m,cnt,dot,line,head[100001],vis[100001]; struct uio{ ll nxt,to; }edge[200001]; void add(ll x,ll y) { edge[++cnt].nxt=head[x]; edge[cnt].to=y; head[x]=cnt; } void dfs(ll x,ll fa) { for(ll i=head[x];i;i=edge[i].nxt) { ll y=edge[i].to; if(y==fa) continue; dfs(y,x); if(!vis[x]&&!vis[y]) { vis[x]=vis[y]=1; if(dot<m) line++; dot+=2; } } } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%lld",&T); while(T--) { cnt=dot=line=0; memset(head,0,sizeof(head)); memset(vis,0,sizeof(vis)); scanf("%lld%lld",&n,&m); for(ll i=1;i<n;i++) { ll u; scanf("%lld",&u); add(u,i+1),add(i+1,u); } dfs(1,0); if(dot>=m) printf("%d\n",line); else printf("%d\n",m-line); } return 0; }