8.12 纪中集训 Day12

T1少女觉

Description

在幽暗的地灵殿中,居住着一位少女,名为古明地觉。
据说,从来没有人敢踏入过那座地灵殿,因为人们恐惧于觉一族拥有的能力——读心。
掌控人心者,可控天下。
 
咳咳。
人的记忆可以被描述为一个黑块(B)与白块(W)的序列,其中情感值被定义为序列中黑块数量与白块数量之比。
小五口在发动读心术时,首先要解析人的记忆序列,因此,需要将序列分割为一些段,并且要求每一段记忆序列的情感值都相等。
下面给出两个例子:
BWWWBB -> BW + WWBB (Ratio=1:1)
WWWBBBWWWWWWWWWB -> WWWB + BBWWWWWW + WWWB (Ratio=3:1)
现在小五手上有一个人的记忆序列,她想要知道,如何将手中的记忆序列分成尽可能多的段呢?

Input

第一行包含一个正整数T,代表数据组数。
对于每一组测试数据,第一行包含一个正整数N。
接下来N行描述一个序列,每行包含一个正整数K和一个大写字母C,表示序列接下来有连续K个颜色为C的方块。

Output

对于每组测试数据输出一行一个正整数,表示最多分成的段数。

Sample Input

3
3
1 B
3 W
2 B
4
3 W
3 B
9 W
1 B
2
2 W
3 W

Sample Output

2
3
5

Data Constraint

对于10%的数据,n<=15
对于20%的数据,n<=500
另有30%的数据,K=1
另有30%的数据,K<=50
对于100%的数据,N<=10^5,序列长度不超过10^9
保证对于全部测试点,输入文件行数不超过2.5*10^6

考场思路/正解

贪心,每组数据的黑白比例一定是固定的,我们只要从左到右扫过去,符合这个比值就ans++,然后就愉快都解决了。

不过考场上我忘记开long long ,所以没有A

Code

#include<cstdio>
#include<algorithm>
#define LL long long
#define NAME "silly"
using namespace std;

LL T,n,k[100010],slw,slb,s1,s2,ans;
char s[100010][2];

void Open()<%freopen(NAME".in","r",stdin);freopen(NAME".out","w",stdout);%>

int main()
{
    Open();
    scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld",&n);
        ans=0,slb=0,slw=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%s",&k[i],s[i]);
            if(s[i][0]=='B')
                slb+=k[i];
            else
                slw+=k[i];
        }
        if(slb==0)
        {
            printf("%lld\n",slw);
            continue;
        }
        if(slw==0)
        {
            printf("%lld\n",slb);
            continue;
        }
        s1=0,s2=0;
        for(int i=1;i<=n;i++)
        {
            if(s[i][0]=='B')
            {
                if((s1*slb)%slw!=0)
                {
                    s2+=k[i];
                    continue;
                }
                if(s2<s1*slb/slw && s1*slb/slw<=s2+k[i])
                    ans++;
                s2+=k[i];
            }
            else
            {
                if((s2*slw)%slb!=0)
                {
                    s1+=k[i];
                    continue;
                }    
                if(s1<s2*slw/slb && s2*slw/slb<=s1+k[i])
                    ans++;
                s1+=k[i];
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
} 

T2灵知的太阳信仰

Description

在炽热的核熔炉中,居住着一位少女,名为灵乌路空。
据说,从来没有人敢踏入过那个熔炉,因为人们畏缩于空所持有的力量——核能。
核焰,可融真金。
 
咳咳。
每次核融的时候,空都会选取一些原子,排成一列。然后,她会将原子序列分成一些段,并将每段进行一次核融。
一个原子有两个属性:质子数和中子数。
每一段需要满足以下条件:
1、同种元素会发生相互排斥,因此,同一段中不能存在两个质子数相同的原子。
2、核融时,空需要对一段原子加以防护,防护罩的数值等于这段中最大的中子数。换句话说,如果这段原子的中子数最大为x,那么空需要付出x的代价建立防护罩。求核融整个原子序列的最小代价和。

Input

第一行一个正整数N,表示原子的个数。
接下来N行,每行两个正整数pi和ni,表示第i个原子的质子数和中子数。

Output

输出一行一个整数,表示最小代价和。

Sample Input

5
3 11
2 13
1 12
2 9
3 13

Sample Output

26

Data Constraint

对于20%的数据,1<=n<=100
对于40%的数据,1<=n<=1000
对于100%的数据,1<=n<=10^5,1<=pi<=n,1<=ni<=2*10^4

考场思路

本来以为是一道非常简单的区间DP题,结果愣是没有做出来。

正解

好像就是区间DP,不过要用单调栈和set来优化罢了(改了一晚上)

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
#define NAME "array"
using namespace std;

int n,L=1,R;
int u[100010],v[100010],l[100010],book[20020],q[100010],p[100010],f[100010];
multiset<int> zx;

void Open()<%freopen(NAME".in","r",stdin);freopen(NAME".out","w",stdout);%>

int main()
{
    Open();
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&u[i],&v[i]);
        l[i]=max(l[i-1],book[u[i]]+1);
        book[u[i]]=i;
    }
    memset(f,0x3f,sizeof f); 
    f[0]=0;
    for(int i=1;i<=n;i++)
    {
        while(L<=R && q[L]<l[i])
            zx.erase(p[L]),L++;
        while(L<=R && v[q[R]]<v[i])
            zx.erase(p[R]),R--;
        q[++R]=i;
        p[R]=f[q[R-1]]+v[i];
        zx.insert(p[R]);
        zx.erase(p[L]);
        zx.insert(p[L]=f[l[i]-1]+v[q[L]]);
        f[i]=*zx.begin();
    }
    printf("%d",f[n]);
    return 0;
}

T3多段线性函数

Description

Input

Output

输出文件名为linear.out。
输出一行两个自然数,用空格隔开,依次为L和R。

Sample Input

5
1 3
2 3
3 5
5 5
6 7

Sample Output

3 5

Data Constraint

正解

有点玄学,(其实好像可以用数学证明,只不过我不会,改日心情好时再来证吧!)

Code

#include<cstdio>
#include<algorithm>
#define NAME "linear"
using namespace std;

int n;
int sz[200020];

void Open()<%freopen(NAME".in","r",stdin);freopen(NAME".out","w",stdout);%>

int main()
{
    Open();
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&sz[i],&sz[i+n]);
    sort(sz+1,sz+1+2*n);
    printf("%d %d",sz[n],sz[n+1]);
    return 0;
}

  T4DY引擎

Description

BOSS送给小唐一辆车。小唐开着这辆车从PKU出发去ZJU上课了。
众所周知,天朝公路的收费站超多的。经过观察地图,小唐发现从PKU出发到ZJU的所有路径只会有N(2<=N<=300)个不同的中转点,其中有M(max(0, N-100) <=M<=N)个点是天朝的收费站。N个中转点标号为1…N,其中1代表PKU,N代表ZJU。中转点之间总共有E(E<=50,000)条双向边连接。
每个点还有一个附加属性,用0/1标记,0代表普通中转点,1代表收费站。当然,天朝的地图上面是不会直接告诉你第i个点是普通中转点还是收费站的。地图上有P(1<=P<=3,000)个提示,用[u, v, t]表示:[u, v]区间的所有中转点中,至少有t个收费站。数据保证由所有提示得到的每个点的属性是唯一的。
车既然是BOSS送的,自然非比寻常了。车子使用了世界上最先进的DaxiaYayamao引擎,简称DY引擎。DY引擎可以让车子从U瞬间转移到V,只要U和V的距离不超过L(1<=L<=1,000,000),并且U和V之间不能有收费站(小唐良民一枚,所以要是经过收费站就会停下来交完钱再走)。
DY引擎果然是好东西,但是可惜引擎最多只能用K(0<=K<=30)次。

Input

第一行有6个整数N,M,E,P,L,K分别代表:N个中转点,M个收费站,E条边,P个提示,DY引擎的有效距离L,DY引擎的使用次数K。
接下去E行,每行有3个整数u,v,w(1<=u, v<=N; 1<=w<=1,000,000)表示:u和v之间有一条长度为w的双向边。
接下去P行,每行有3个整数u,v,t(1<=u<=v<=N; 0<=t<=u-v+1)表示: [u, v] 标号区间至少有t个收费站。

Output

输出一个整数,表示小唐从PZU开到ZJU用的最短距离(瞬间转移距离当然是按0来计算的)。

Sample Input

6 2 6 2 5 1

1 2 1

2 3 2

3 6 3

1 4 1

4 5 2

5 6 3

2 5 2

4 6 2

Sample Output

1

【样例解释】

    4、5是收费站。1->2(1)->6(1)

Data Constraint

对于30%的数据保证: 

2<=N<=30,max(0, N-10) <=M<=N,0<=k<=10

对于100%的数据保证:

 2<=N<=300,max(0, N-100) <=M<=N,E<=50,000,1<=P<=3,000,1<=L<=1,000,000,0<=K<=30

考场思路

空白

正解

有空探索呀

 

总结

Fighting!

距 NOIp2019 还剩 88 天       祭

posted @ 2019-08-13 21:43  Thm-V  阅读(266)  评论(0编辑  收藏  举报