YYHSOI模拟赛题解(T2零件加工)
题目描述
工匠小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。
这一道题目我们可以发现,用DP做是存在后效性的。那么,还有什么办法能在线性的时间内,只有贪心了。我们假设目前取过的数,时间已经有S了,那么对于两个工件而言,如果一个工件的时间除以它的价格比另一个时间除以价格更优则我们先取这个工件。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 7 using namespace std; 8 9 struct node 10 { 11 long long t,s; 12 }; 13 14 int N; 15 long long M; 16 long long f[100005]; 17 node a[100005]; 18 19 bool cmp1(node i,node j) 20 { 21 return i.t * j.s < i.s * j.t; 22 } 23 24 long long mul(long long a,long long b) 25 { 26 long long tmp=0; 27 while (b) 28 { 29 if (b % 2 == 1) 30 { 31 tmp=(tmp + a) % M; 32 } 33 a=(a + a) % M; 34 b=b / 2; 35 } 36 return tmp; 37 } 38 39 int main() 40 { 41 scanf("%d%lld",&N,&M); 42 for (int i=1; i<=N; i++) 43 { 44 scanf("%lld%lld",&a[i].t,&a[i].s); 45 } 46 sort(a+1,a+N+1,cmp1); 47 long long ans=0; 48 long long pre=0; 49 for (int i=2; i<=N; i++) 50 { 51 pre=(pre + a[i-1].t) % M; 52 long long tmp=mul(pre,a[i].s % M) % M; 53 ans=(ans + tmp) % M; 54 } 55 printf("%lld\n",ans); 56 }