零件加工(贪心)
题目描述
工匠小K最近有n个零件需要加工。每个零件都需要ti天的时间来完成,每个零件每延迟一天加工都要缴纳一定的罚金si。延迟的天数为从今天算起到该工作开始的那天,第一个零件加工没有罚金。现在小K想知道怎样安排加工顺序可以使他要交的罚金最少,最少是多少。
这个数可能会很大,请输出这个数对m取模后的结果。
输入
输入文件名为process.in。
输入第一行为一个整数n,表示需要加工的零件总数。
第二行为一个整数m,表示答案要对m取模。
第3~n+2行,每行两个整数ti和si。
输出
输出文件名为process.out。
输出仅一行,一个整数,表示小K最少要缴纳的罚金对m取模的结果。
样例输入
process.in
2
100
2 33
33 2
process.out
4
process.in
4
100
3 3
6 4
2 2
8 5
process.out
81
样例输出
【输入输出样例解释1】先加工第一个,需要2天时间,再加工第二个。需要缴纳的罚金为2×2=4。【输入输出样例解释2】如果按照1→2→3→4的顺序进行加工,需要缴纳的罚金为0×3+3×4+(3+6)×2+ (3+6+2)×5=85; 最佳方案是3→1→2→4,此时需要缴纳的罚金为0×2+2×3+(2+3)×4+(2+3+6)×5=81。
提示
【数据范围】
对于40%的数据,0<n≤10,000,0<ti,si≤10,000;
对于80%的数据,0<n≤100,000,0<ti,si≤2×10^9,0<m≤10^8;
对于100%的数据,0<n≤100,000,0<ti,si≤2×10^9,0<m≤10^18。
solution:
看数据范围,n很大,时间复杂度只能是O(n)或者O(n lgn)的,题目要求安排顺序,dp优化达不到这个时间的。排列是一个非常巨大的工程。然后剩下的路就不多了。图论?这不想,这怎么连边啊?只能往贪心想。t[i]小的希望放前面,s[i]小的希望放后面。根据差排序?几个差相等的零件,挂了!商?试一下商相等的情况,没问题。感觉有希望,再试几组数据,没有问题。想办法去证明,结果是可以证明的。
于是这就是一道排序题了。还有一个巨坑,0<m≤10^18,统计答案时用乘法会超过long long,加法会TLE,高精度太麻烦,偷懒用了类似快速幂的快速加。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstdlib> #include<cstring> using namespace std; int n; long long m,ans,s[200000]; struct node{ long long a,b; }x[200000]; bool cmp(node aa,node bb){ return aa.a*bb.b<bb.a*aa.b; } long long cf(long long x,long long y){ if(y==1) return x%m; long long tmp=cf(x,y>>1)%m; if(y&1) return (tmp+tmp+x)%m; else return (tmp+tmp)%m; } int main(){ scanf("%d",&n); scanf("%lld",&m); for(int i=1;i<=n;i++) scanf("%lld%lld",&x[i].a,&x[i].b); sort(x+1,x+1+n,cmp); ans=0; s[0]=0; for(int i=1;i<=n;i++) s[i]=(s[i-1]+x[i].a)%m; for(int i=1;i<=n;i++) ans=(ans+cf(s[i-1],x[i].b%m))%m; printf("%lld\n",ans); return 0; }