CF补题[长期更新]

现在主要写div2的题,从前往后写到实在不会写,思路很简单的就不记录了

- E. Game with String

题意:两个人玩游戏,AB都知道原字符串s,A将s从下表为k的位置断开,左右交换组成新的字符穿t
B猜k,求b的赢得几率
B有两个手段
1.先看新字符串t的首字母也就是s[k+1]
2.看完首字母后 决定看t的任意一个字符
最后求B能百分百猜对t的概率

简单的博弈概率题目
图书馆要关了,先存档一下,明天再写

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
const int N=5e3;
int n,len;
char str[N+10];
char ss[N+10];
bool have[26];
vector<string> arr[26];


void merge(char *s,int t)
{
    int top=0;
    for(int i=t;i<len;i++)
        s[top++]=str[i];
    for(int i=0;i<t;i++)
        s[top++]=str[i];
    s[top]='\0';
}



int main()
{
    while(~scanf("%s",str))
    {
        //init
        mem(have);
        for(int i=0;i<26;i++)arr[i].clear();
        len=0;
        //get len
        for(int i=0;str[i]!='\0';i++)
        {
            len++;
            have[str[i]-'a']=true;
        }
        //得到字符串矩阵
        int top=0;//arr的下标
        for(int i=0;i<26;i++)if(have[i])
        {
            char c='a'+i;
            for(int j=0;j<len;j++)
            {
                if(str[j]==c)
                {
                    merge(ss,j);
                    printf("%s\n",ss);
                    arr[top].push_back(string(ss));
                }
            }
            top++;
        }
        double ans = 0;
        for(int i=0;i<top;i++)
        {
            int len1 = arr[i].size();
            int maxt=0;
            for(int j=1;j<len;j++)
            {
                int cnt[26];
                mem(cnt);
                int tt=0;
                for(int k=0;k<len1;k++)
                {
                    char tp = arr[i][k][j]-'a';
                    cnt[tp]++;
                }
                for(int k=0;k<26;k++)if(cnt[k]==1)tt++;
                maxt = max(maxt,tt);
            }
            ans+=(double)maxt;
        }
        double p = ans/len;
        printf("%.14f\n",p);
    }
    return 0;
}

题意有点误会,所以写错了,在所有字符串排列成的矩阵中
比如
actactictict
actictictact
ctictactacti
ctactacticti
ctacticticta
ctictictacta
ictictactact
ictactactict
tictictactac
tictactactic
tactactictic
tactictictac
ac代码只要对所有行sigma(max(每一列的不重复出现的字母))/len(str)即可
感觉很坑,不是求猜正确的概率,
而是求,随机一个k,看一个首字母,存在能100%确定t的概率。

- Zabre 469 div2 C

比赛的时候没看清楚题目,单个的0,和00 都是合法的,所以末尾剩下的0就不用考虑匹配了,这样就很简单
只要考虑1,充分利用现有的0,把1都给放了,(按照题意0101的规则放置)
这样考虑,输出-1的情况只有两个

  • 没有0来放后面的1
  • 最后放完了还有1在最后面
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <list>
#include <queue>
/*
#include <cmath>
#include <cstdlib>
#include <algorithm>
*/
#define mem(x) memset(x,0,sizeof(x))


using namespace std;
const int N=2e5+10;
int queue_tail[N];//保存每一个子序列的尾部
vector<int> T[N];//保存子序列的下标
int main()
{
    string s;
    cin>>s;
    int len=0;
    queue<int> zero,one;//暴力搜索能放的位置会TLE,把能放的位置放在队列里
    int top=0;//每个多出来的0都放在top位置,以便继续放后面的1;
    bool fg=true;
    mem(queue_tail);
    for(int i=0;i<s.length();i++)
    {
        char tp = s[i];
        if(tp=='0')
        {
            int loc;
            if(zero.empty())
            {
                loc=top++;
            }
            else
            {
                loc = zero.front();
                zero.pop();
            }
            T[loc].push_back(i+1);
            queue_tail[loc]=0;
            one.push(loc);
        }
        else
        {
            int loc;
            if(one.empty())
            {
                fg=false;
                break;
            }
            else
            {
                loc = one.front();
                one.pop();
            }
            T[loc].push_back(i+1);
            queue_tail[loc]=1;
            zero.push(loc);
        }
    }
    for(int i=0;i<top;i++)
    {
        if(queue_tail[i]==1)
        {
            fg=false;
            break;
        }
    }
    if(fg)
    {
        int i=0;
        printf("%d\n",top);
        int len;
        while(true)
        {
            len = T[i].size();
            if(len==0)break;
            printf("%d ",len);
            for(int j=0;j<len;j++)
            {
                printf("%d%s",T[i][j],j==len-1?"\n":" ");
            }
            i++;
        }
    }
    else
    {
        cout<<-1<<endl;
    }
    return 0;
}

E. Data Center Maintenance

  • 题意:

    题目很长读了半天,就是几个个东西

    1. 有n个数据中心
    2. 有m个客户
    3. 每天有h小时
    4. 数据中心在某几个小时点会进行一小时的维护
    5. 每个客户能从两个不同的数据中心获取数据
    6. 问题的前提是任一客户在任意时间都至少有一个数据中心不在维护
    7. 问题的输出就是,关键 在保证6的情况下,取一个最小子集,将他们延后一个小时
    8. 试想,如果原来满足6,那么把所有维护机都往后延后一个小时,还是能保证6,所以每个问题都至少有一个解,就是全部拿来实验

尝试解题

数据n,m,h的范围都是1e5;
nlogn的复杂度才能保证不TLE

对于第二个样例(我们吧数据中心的下标列在客户数据后面)

4 5 4
2 1 0 3

4 3 0 3
3 2 0 1
1 2 2 1
1 4 2 3
1 3 2 0

不难看出来,如果一个客户的两个客户中心相差一个小时,那早更新的那个如果加入实验,必然导致另外一个也加入实验,对于一个二元关系我们可以建立一个图来解决
例如第2个客户,3 2
那么数据中心3连一条有向弧到2;表示,如果数据中心3,如果加入试验,那么2也必须加入试验。
那么问题就转换成为
求一个最小的连通块
接下来代码就很好写了
写着发现没这么简单
应该要先将这个有向图缩点 成为一个DAG
然后 取 缩点后的所有出度为0的点 中 点的数目最小的那个连通块,才能满足题意。
缩点代码参考我的另外一篇blog
本题代码

猜你喜欢

转载自blog.csdn.net/zhonglong_lin/article/details/79477376