Hello 2018
You are preparing for an exam on scheduling theory. The exam will last for exactly T milliseconds and will consist of n problems. You can either solve problem i in exactly ti milliseconds or ignore it and spend no time. You don't need time to rest after solving a problem, either.
Unfortunately, your teacher considers some of the problems too easy for you. Thus, he assigned an integer ai to every problem i meaning that the problem i can bring you a point to the final score only in case you have solved no more than ai problems overall (including problem i).
Formally, suppose you solve problems p1, p2, ..., pk during the exam. Then, your final score s will be equal to the number of values of j between 1 and k such that k ≤ apj.
You have guessed that the real first problem of the exam is already in front of you. Therefore, you want to choose a set of problems to solve during the exam maximizing your final score in advance. Don't forget that the exam is limited in time, and you must have enough time to solve all chosen problems. If there exist different sets of problems leading to the maximum final score, any of them will do.
The first line contains two integers n and T (1 ≤ n ≤ 2·105; 1 ≤ T ≤ 109) — the number of problems in the exam and the length of the exam in milliseconds, respectively.
Each of the next n lines contains two integers ai and ti (1 ≤ ai ≤ n; 1 ≤ ti ≤ 104). The problems are numbered from 1 to n.
In the first line, output a single integer s — your maximum possible final score.
In the second line, output a single integer k (0 ≤ k ≤ n) — the number of problems you should solve.
In the third line, output k distinct integers p1, p2, ..., pk (1 ≤ pi ≤ n) — the indexes of problems you should solve, in any order.
If there are several optimal sets of problems, you may output any of them.
5 300
3 100
4 150
4 80
2 90
2 300
2
3
3 1 4
2 100
1 787
2 788
0
0
2 100
2 42
2 58
2
2
1 2
In the first example, you should solve problems 3, 1, and 4. In this case you'll spend 80 + 100 + 90 = 270 milliseconds, falling within the length of the exam, 300 milliseconds (and even leaving yourself 30 milliseconds to have a rest). Problems 3 and 1 will bring you a point each, while problem 4 won't. You'll score two points.
In the second example, the length of the exam is catastrophically not enough to solve even a single problem.
In the third example, you have just enough time to solve both problems in 42 + 58 = 100 milliseconds and hand your solutions to the teacher with a smile.
这题我是二分答案做的。通过二分将一个二维的问题削成一维,削掉了答题数目限制这一维,然后把大于等于ans的摘出来排个序,加起来判断一下就ok了 复杂度O(nlogn)
然后我看别人的做法是优先队列,大概就是按花销时间排序,然后一个一个加入到答案队列中,如果答案队列的size大于第一个限制答题数目就踢掉头,优先队列的排序规则
是答题数目限制为主,然后时间为辅,扫一遍也可以,复杂度也是O(logn).
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2e5+88; struct node{ int number,id,time; bool operator < (const node &A)const{ return number!=A.number?number<A.number:time<A.time; } }tc[N]; pair<int,int>T[N]; int n,t,Ans[N]; bool Ju(int k){ int l=1,r=n,ay=-1; while(l<=r) { int mid=(l+r)>>1; if(tc[mid].number>=k) ay=mid,r=mid-1; else l=mid+1; } if(ay==-1) if(!k) return 1;else return 0; if(ay+k-1>n) return 0; int tot=0,now=0; for(int i=ay;i<=n;++i) T[++tot].first=tc[i].time,T[tot].second=tc[i].id; sort(T+1,T+tot+1); for(int i=1;i<=k;++i) if(now+T[i].first>t) return 0;else now+=T[i].first; for(int i=1;i<=k;++i) Ans[i]=T[i].second; return 1; } int main(){ scanf("%d%d",&n,&t); for(int i=1;i<=n;++i) { scanf("%d%d",&tc[i].number,&tc[i].time); tc[i].id=i; } sort(tc+1,tc+n+1); int ans,l=0,r=n; while(l<=r) { int mid=(l+r)>>1; if(Ju(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n%d\n",ans,ans); if(!ans) puts(""); else for(int i=1;i<=ans;++i) printf("%d%c",Ans[i],i==ans?'\n':' '); }
There is a chess tournament in All-Right-City. n players were invited to take part in the competition. The tournament is held by the following rules:
- Initially, each player plays one game with every other player. There are no ties;
- After that, the organizers build a complete directed graph with players as vertices. For every pair of players there is exactly one directed edge between them: the winner of their game is the startpoint of this edge and the loser is the endpoint;
- After that, the organizers build a condensation of this graph. The condensation of this graph is an acyclic complete graph, therefore it has the only Hamiltonian path which consists of strongly connected components of initial graph A1 → A2 → ... → Ak.
- The players from the first component A1 are placed on the first
places, the players from the component A2 are placed on the next
places, and so on.
- To determine exact place of each player in a strongly connected component, all the procedures from 1 to 5 are repeated recursively inside each component, i.e. for every i = 1, 2, ..., k players from the component Ai play games with each other again, and so on;
- If a component consists of a single player, then he has no more rivals, his place is already determined and the process stops.
The players are enumerated with integers from 1 to n. The enumeration was made using results of a previous tournament. It is known that player i wins player j (i < j) with probability p.
You need to help to organize the tournament. Find the expected value of total number of games played by all the players.
It can be shown that the answer can be represented as , where P and Q are coprime integers and
. Print the value of P·Q - 1 modulo 998244353.
If you are not familiar with any of the terms above, you can read about them here.
The first line of input contains a single integer n (2 ≤ n ≤ 2000) — the number of players.
The second line contains two integers a and b (1 ≤ a < b ≤ 100) — the numerator and the denominator of fraction .
In the only line print the expected value of total number of games played by all the players. Print the answer using the format above.
3
1 2
4
3
4 6
142606340
4
1 2
598946623
In the first example the expected value is 4.
In the second example the expected value is .
In the third example the expected value is .
对顶点数目为n的情况进行分类,分类标准是最后一个联通块的大小。
然后原文只有括号里的加法没有解释,加法就是j个顶点已经确定要当作一个新的整体来做了,所以需要特殊处理成初始状态
就是本来是 增量=ans[j]+ans[i-j]+j*(i-j) 但是显然把j个当成一个强连通块就相当于多做一次喽。然后加上j*(i-j)就可以了
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int P=998244353; const int N=2008; int p0[N],p1[N],cp[N][N],strong[N],ans[N]; int ksm(int a,int b){ int ans=1; while(b){ if(b&1) ans=1LL*ans*a%P; b>>=1; a=1LL*a*a%P; } return ans; } int main(){ int n,a,b,win,lost; scanf("%d%d%d",&n,&a,&b); p0[0]=p1[0]=1; lost=1LL*a*ksm(b,P-2)%P,win=1LL*(b-a)*ksm(b,P-2)%P; for(int i=1;i<=n;++i) p0[i]=1LL*p0[i-1]*lost%P,p1[i]=1LL*p1[i-1]*win%P; for(int i=0;i<=n;++i) { cp[i][0]=1; for(int j=1;j<=i;++j) cp[i][j]=1LL*(1LL*cp[i-1][j-1]*p0[i-j]+1LL*cp[i-1][j]*p1[j])%P; } for(int i=1;i<=n;++i) strong[i]=1; for(int i=2;i<=n;++i) for(int j=1;j<i;++j) strong[i]=1LL*(strong[i]-1LL*cp[i][j]*strong[j]%P+P)%P; for(int i=1;i<=n;++i) { for(int j=1;j<i;++j) ans[i]=1LL*(ans[i]+1LL*strong[j]*cp[i][j]%P*(1LL*j*(i-j)+1LL*j*(j-1)/2+ans[j]+ans[i-j])%P)%P; ans[i]=1LL*(ans[i]+1LL*strong[i]*(i*(i-1)/2))%P; ans[i]=1LL*ans[i]*ksm(1-strong[i],P-2)%P; ans[i]=(ans[i]+P)%P; } printf("%d\n",ans[n]); }