Hello 2018

D. Too Easy Problems
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Input

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.

Output

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.

Examples
Input
5 300
3 100
4 150
4 80
2 90
2 300
Output
2
3
3 1 4
Input
2 100
1 787
2 788
Output
0
0

Input
2 100
2 42
2 58
Output
2
2
1 2
Note

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':' ');
}

 

F. Strongly Connected Tournament
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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:

  1. Initially, each player plays one game with every other player. There are no ties;
  2. 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;
  3. 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.
  4. 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.
  5. 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;
  6. 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.

Input

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 .

Output

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.

Examples
Input
3
1 2
Output
4
Input
3
4 6
Output
142606340
Input
4
1 2
Output
598946623
Note

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]);
}

 

 

 

 

 

 

 

 

E. Logical Expression

time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a boolean function of three variables which is defined by its truth table. You need to find an expression of minimum length that equals to this function. The expression may consist of:

  • Operation AND ('&', ASCII code 38)
  • Operation OR ('|', ASCII code 124)
  • Operation NOT ('!', ASCII code 33)
  • Variables x, y and z (ASCII codes 120-122)
  • Parentheses ('(', ASCII code 40, and ')', ASCII code 41)

If more than one expression of minimum length exists, you should find the lexicographically smallest one.

Operations have standard priority. NOT has the highest priority, then AND goes, and OR has the lowest priority. The expression should satisfy the following grammar:

E ::= E '|' T | T

T ::= T '&' F | F

F ::= '!' F | '(' E ')' | 'x' | 'y' | 'z'

Input

The first line contains one integer n — the number of functions in the input (1 ≤ n ≤ 10 000).

The following n lines contain descriptions of functions, the i-th of them contains a string of length 8 that consists of digits 0 and 1 — the truth table of the i-th function. The digit on position j (0 ≤ j < 8) equals to the value of the function in case of , and .

Output

You should output n lines, the i-th line should contain the expression of minimum length which equals to the i-th function. If there is more than one such expression, output the lexicographically smallest of them. Expressions should satisfy the given grammar and shouldn't contain white spaces.

Example
Input
4
00110011
00000111
11110000
00011111
Output
y
(y|z)&x
!x
x|y&z
Note

The truth table for the second function:

.出处

 

这题给我的感觉就是观察很重要,原文链接里画的很清楚了,6个操作保证F[i],T[i],E[i]三个数组形成一个闭合完整的群,然后其实最短路的做法也跟这个差不多,最根本的还是

这6个操作所带来的转换。优先级高的可以随意转化为优先级低的,然后同时要兼顾到& | !这三个操作就可以形成一个密闭的“群”的样子。。

复制代码
#include<string>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int X=15,Y=51,Z=85;
string E[256],T[256],F[256];
bool flag=1;
void upd(string &A,const string &B){
    if(A=="") {
        A=B,flag=1;return;
    }
    int t1=A.size(),t2=B.size();
    if(t1>t2) A=B,flag=1;
    else if(t1==t2&&A>B) A=B,flag=1;
    return; 
}
int main(){
    F[X]='x',F[Y]='y',F[Z]='z';
    while(flag) {
        flag=0;
        for(int i=0;i<=255;++i) if(T[i]!="") for(int j=0;j<=255;++j) if(F[j]!="") upd(T[i&j],T[i]+'&'+F[j]);
        for(int i=0;i<=255;++i) if(E[i]!="") for(int j=0;j<=255;++j) if(T[j]!="") upd(E[i|j],E[i]+'|'+T[j]);
        for(int i=0;i<=255;++i) if(E[i]!="") upd(F[i],'('+E[i]+')');
        for(int i=0;i<=255;++i) if(F[i]!="") upd(F[i^255],'!'+F[i]);
        for(int i=0;i<=255;++i) if(F[i]!="") upd(T[i],F[i]);
        for(int i=0;i<=255;++i) if(T[i]!="") upd(E[i],T[i]);
    }
    int T,x;
    char s[10];
    for(scanf("%d",&T);T--;){
        scanf("%s",s);
        x=0;
        for(int i=0;i<=7;++i) x=(x<<1)+s[i]-'0';
        cout<<E[x]<<endl;
    }
}
复制代码
 
posted @ 2018-01-31 15:17  Billyshuai  阅读(177)  评论(0编辑  收藏  举报