[CSP-S模拟测试]:Emotional Flutter(贪心) [CSP-S模拟测试]:Emotional Flutter(贪心)

 

题目传送门(内部题51)


输入格式

第一行一个整数tt表示数据组数。
每组数据的第一行有三个整数s,k,ns,k,n。
第二行有nn个整数A1,A2,...,AnA1,A2,...,An,依次表示黑白条的长度。


输出格式

若能通过输出"TAK""TAK",否则输出"NIE""NIE"。


样例

样例输入:

2
2 8 7
2 5 6 3 2 1 2
2 8 4
1 6 7 4

样例输出:

TAK
NIE


数据范围与提示

样例解释:

数据范围:

30%30%的数据,n1300n⩽1300; 
50%50%的数据,n22,000n⩽22,000; 
100%100%的数据,2n500,000,1s<k109,1Ai109,1t102⩽n⩽500,000,1⩽s<k⩽109,1⩽Ai⩽109,1⩽t⩽10。 
数据有梯度。输入文件较大请使用读入优化。


题解

其实就是一个贪心,主要是策略很难想。

首先来处理脚的长度,我们可以将所有的黑块都延长ss,所有的白块左端点向右移动ss,这样就相当与忽略了脚的长度。

然后会有一些特判的情况,对于我的贪心策略,我们只需要用到当一个黑块长度大于kk时,肯定跳不过去,所以直接输出"NIE""NIE"即可。

现在来讲对于一般情况,我是如何判断的。

首先,将所有的黑块的左端点和右端点分别modkmodk,那么我们是不能在这段区间进行起跳的;如果出现modkmodk完之后右端点小于左端点,那么区间[0,r][0,r]和区间[l,k1][l,k−1]是不能起跳的。

之后我们只需要将所有的不能跳的区间排个序,然后我们只需要找到一个可以起跳的点即可。

细节比较多,慢慢调吧……

时间复杂度:Θ(nlogn)Θ(nlog⁡n)。

期望得分:100100分。

实际得分:100100分。


代码时刻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<bits/stdc++.h>
using  namespace  std;
struct  rec{ long  long  l,r;}e[10000000];
long  long  s,k,n;
long  long  sum[5000001];
long  long  lft[5000001],rht[5000001],wsq;
int  top;
bool  flag;
bool  cmp(rec a,rec b){ return  a.l==b.l?a.r<b.r:a.l<b.l;}
int  main()
{
     int  T;scanf( "%d" ,&T);
     while (T--)
     {
         scanf( "%lld%lld%lld" ,&s,&k,&n);
         top=flag=wsq=0;
         for ( int  i=1;i<=n;i++)
         {
             long  long  a;
             scanf( "%lld" ,&a);
             if (i&1)a+=s;
             else {a-=s;a%=k;}
             if (a>k)flag=1;
             sum[i]=sum[i-1]+a;
             if (i&1)
             {
                 lft[i]=sum[i-1]+1;
                 rht[i]=sum[i]-1;
             }
         }
         if (((n&1)&&sum[n]<=k)||((!(n&1))&&sum[n-1]<=k)){puts( "TAK" ); continue ;}
         if (flag){puts( "NIE" ); continue ;}
         for ( int  i=1;i<=n;i+=2)
         {
             lft[0]=lft[i]%k;
             rht[0]=rht[i]%k;
             if (rht[0]<lft[0])
             {
                 e[++top]=(rec){0,rht[0]};
                 e[++top]=(rec){lft[0],k-1};
             }
             else  e[++top]=(rec){lft[0],rht[0]};
         }
         sort(e+1,e+top+1,cmp);
         if (e[1].l){puts( "TAK" ); goto  nxt;}
         for ( int  i=1;i<=top;i++)
         {
             if (wsq+1<e[i].l){puts( "TAK" ); goto  nxt;}
             wsq=max(wsq,e[i].r);
         }
         if (wsq<k-1){puts( "TAK" ); continue ;}
         puts( "NIE" );
         nxt:;
     }
     return  0;
}

rp++


题目传送门(内部题51)


输入格式

第一行一个整数tt表示数据组数。
每组数据的第一行有三个整数s,k,ns,k,n。
第二行有nn个整数A1,A2,...,AnA1,A2,...,An,依次表示黑白条的长度。


输出格式

若能通过输出"TAK""TAK",否则输出"NIE""NIE"。


样例

样例输入:

2
2 8 7
2 5 6 3 2 1 2
2 8 4
1 6 7 4

样例输出:

TAK
NIE


数据范围与提示

样例解释:

数据范围:

30%30%的数据,n1300n⩽1300; 
50%50%的数据,n22,000n⩽22,000; 
100%100%的数据,2n500,000,1s<k109,1Ai109,1t102⩽n⩽500,000,1⩽s<k⩽109,1⩽Ai⩽109,1⩽t⩽10。 
数据有梯度。输入文件较大请使用读入优化。


题解

其实就是一个贪心,主要是策略很难想。

首先来处理脚的长度,我们可以将所有的黑块都延长ss,所有的白块左端点向右移动ss,这样就相当与忽略了脚的长度。

然后会有一些特判的情况,对于我的贪心策略,我们只需要用到当一个黑块长度大于kk时,肯定跳不过去,所以直接输出"NIE""NIE"即可。

现在来讲对于一般情况,我是如何判断的。

首先,将所有的黑块的左端点和右端点分别modkmodk,那么我们是不能在这段区间进行起跳的;如果出现modkmodk完之后右端点小于左端点,那么区间[0,r][0,r]和区间[l,k1][l,k−1]是不能起跳的。

之后我们只需要将所有的不能跳的区间排个序,然后我们只需要找到一个可以起跳的点即可。

细节比较多,慢慢调吧……

时间复杂度:Θ(nlogn)Θ(nlog⁡n)。

期望得分:100100分。

实际得分:100100分。


代码时刻

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<bits/stdc++.h>
using  namespace  std;
struct  rec{ long  long  l,r;}e[10000000];
long  long  s,k,n;
long  long  sum[5000001];
long  long  lft[5000001],rht[5000001],wsq;
int  top;
bool  flag;
bool  cmp(rec a,rec b){ return  a.l==b.l?a.r<b.r:a.l<b.l;}
int  main()
{
     int  T;scanf( "%d" ,&T);
     while (T--)
     {
         scanf( "%lld%lld%lld" ,&s,&k,&n);
         top=flag=wsq=0;
         for ( int  i=1;i<=n;i++)
         {
             long  long  a;
             scanf( "%lld" ,&a);
             if (i&1)a+=s;
             else {a-=s;a%=k;}
             if (a>k)flag=1;
             sum[i]=sum[i-1]+a;
             if (i&1)
             {
                 lft[i]=sum[i-1]+1;
                 rht[i]=sum[i]-1;
             }
         }
         if (((n&1)&&sum[n]<=k)||((!(n&1))&&sum[n-1]<=k)){puts( "TAK" ); continue ;}
         if (flag){puts( "NIE" ); continue ;}
         for ( int  i=1;i<=n;i+=2)
         {
             lft[0]=lft[i]%k;
             rht[0]=rht[i]%k;
             if (rht[0]<lft[0])
             {
                 e[++top]=(rec){0,rht[0]};
                 e[++top]=(rec){lft[0],k-1};
             }
             else  e[++top]=(rec){lft[0],rht[0]};
         }
         sort(e+1,e+top+1,cmp);
         if (e[1].l){puts( "TAK" ); goto  nxt;}
         for ( int  i=1;i<=top;i++)
         {
             if (wsq+1<e[i].l){puts( "TAK" ); goto  nxt;}
             wsq=max(wsq,e[i].r);
         }
         if (wsq<k-1){puts( "TAK" ); continue ;}
         puts( "NIE" );
         nxt:;
     }
     return  0;
}

rp++

猜你喜欢

转载自www.cnblogs.com/dg9906667/p/11723768.html
今日推荐