Description

在一款电脑游戏中,你需要打败n只怪物(从1到n编号)。为了打败第i只怪物,你需要消耗d[i]点生命值,但怪物死后会掉落血药,使你恢复a[i]点生命值。任何时候你的生命值都不能降到0(或0以下)。请问是否存在一种打怪顺序,使得你可以打完这n只怪物而不死掉

Input

第一行两个整数n,z(1<=n,z<=100000),分别表示怪物的数量和你的初始生命值。
接下来n行,每行两个整数d[i],a[i](0<=d[i],a[i]<=100000)

Output

第一行为TAK(是)或NIE(否),表示是否存在这样的顺序。
如果第一行为TAK,则第二行为空格隔开的1~n的排列,表示合法的顺序。如果答案有很多,你可以输出其中任意一个。

Sample Input

3 5
3 1
4 8
8 3

Sample Output

TAK
2 3 1
 

 

应该都能想到分成两类处理+排序,但按什么排呢?

我们把怪分成两种类型:回血怪和掉血怪考虑。回血怪按扣血升序排列即可。

掉血怪的思路就比较妙比较好Van♂了,最后剩的血量是确定的,那么我们倒序推,则原来的扣血变成了“回血”,原来的回血变成了“扣血”,于是掉血怪也就相当于回血怪了,考虑按“扣血”升序排列,所以正序就是题给回血按降序排列。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<cmath>
#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define For(i,l,r) for(ri i=l;i<=r;i++)
#define Dfor(i,r,l) for(ri i=r;i>=l;i--)
using namespace std;
const int M=1e5+5;
int n,t1,t2;
ll s;
struct node{
    int id,d,a;
}a[M],b[M];
inline ll read(){
    ll f=1,sum=0;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();}
    return f*sum;
}
inline bool cmp1(node x,node y){return x.d<y.d;}
inline bool cmp2(node x,node y){return x.a>y.a;}
int main(){
    n=read(),s=read();
    For(i,1,n){
        int x=read(),y=read();
        if(x<=y) a[++t1].d=x,a[t1].a=y,a[t1].id=i;
        else b[++t2].d=x,b[t2].a=y,b[t2].id=i;
    }
    sort(a+1,a+t1+1,cmp1);
    For(i,1,t1){
        if(s<=a[i].d){cout<<"NIE";return 0;}
        s=s-a[i].d+a[i].a;
    }
    sort(b+1,b+t2+1,cmp2);
    For(i,1,t2){
        if(s<=b[i].d){cout<<"NIE";return 0;}
        s=s-b[i].d+b[i].a;
    }
    cout<<"TAK"<<endl;
    For(i,1,t1) printf("%d ",a[i].id);
    For(i,1,t2) printf("%d ",b[i].id);
    return 0;
}
01-03 12:37