1. 程式人生 > >CF補題[長期更新]

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
本題程式碼