Codeforces Round #110 (Div. 1)

codeforces一個不錯的比賽,雖然我現在還不能參加div1的比賽,但是我還是好好的看了看昨天的那套題。不錯!!

A:Message 這個題栽在了讀題上,Insert one letter to any end of the string.  就是這句話,我怎麼也沒想到,其中的end是端點的意思,也就是在任意一個端點插入字母。好吧,我承認我英語不咋地,其他的倒是還好想,s的第i個字符和u的第j個字符是對應的,u的j後面的字符是插入的,這樣的話,修改的次數就可以唯一的求出,進而求出結果。爲了處理在前面插入的情況,在第一個字符串前面插入2000個字符就是了,前面插入相當於前面修改,ok,結束:

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
#define N 2020
char a[N*2],b[N];
int data[N][N*2];
int main()
{
    scanf("%s",a);
    scanf("%s",b);
    int aa = strlen(a);
    for(int i = 0;i <= aa;i++)
        a[i+2002] = a[i];
    for(int i = 0;i < 2002;i++) a[i] = '@';
    aa = strlen(a);
    int bb = strlen(b);
    //for(int i = aa+1;i > 0;i++) a[i] = a[i-1];
    //for(int i = bb+1;i > 0;i++) b[i] = b[i-1];

    for(int i = 0;i < 2010;i++)
        for(int j = 0;j < i;j++)
            data[i][j] = 200000;
    data[0][0] = 0;
    int re = 900000000;
    for(int i = 1;i <= bb;i++)
        for(int j = i;j <= aa;j++)
        {
            if(b[i-1] == a[j-1])
                data[i][j] = data[i-1][j-1];
            else data[i][j] = data[i-1][j-1]+1;
            re = min(re,bb-i+data[i][j]);
        }
    cout << re << "\n";
    return 0;
}

B:Suspects 這個題,也是有一點技巧的,我覺得挺好玩的。

題目大意是說,n個犯罪嫌疑人中有一個罪犯,n個犯罪嫌疑人分別說一句話:某某是犯罪分子或者某某不是犯罪分子。告訴你有m個說的真話,最後要求輸出的是,這n個人時撒謊是說真話,還是不確定。

思路:首先注意這n個人中只有一個是犯罪分子,另一個要注意的是有m個人說了真話

可以先假設,所有人都不是犯罪分子,那麼就會確定出k個人撒了謊,當我們再分別假設每一個人時犯罪分子,修正這個k,看說謊的人數和題目給的是否相同,如果相同,那麼這個假設是犯罪分子的,就有可能是犯罪分子,否則,這個假設的人一定不是犯罪分子。

然後根據可能是犯罪分子的人的數量分類討論輸出就行了。

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

#define N 100010
int data[N][2];//0¼Ù£¬1Õæ
bool canFalse[N];
int canFalseNum;

int souse[N];
int main()
{
    memset(data,0,sizeof(data));
    memset(canFalse,0,sizeof(canFalse));
    canFalseNum = 0;
    int fals = 0;
    int n,m,t;
    cin >> n >> m;
    for(int i = 1;i <= n;i++)
    {
        cin >> t;
        souse[i] = t;
        if(t > 0)
        {
            fals++;
            data[t][0]++;
        }else
        {
            t = 0-t;
            data[t][1]++;
        }
    }

    for(int i = 1;i <= n;i++)
    {
        if(fals - data[i][0] + data[i][1] == n-m)
        {
            canFalse[i] = 1;
            canFalseNum++;
        }
    }
    if(canFalseNum == 1)
    {
        for(int i = 1;i <= n;i++)
        {
            if( (souse[i] < 0 && canFalse[ 0-souse[i] ] == 0) || (souse[i] > 0 && canFalse[ souse[i] ] == 1) )
                cout << "Truth\n";
            else cout << "Lie\n";
        }
    }
    else
    {
        for(int i = 1;i <= n;i++)
        {
            if( (souse[i] > 0 && canFalse[ souse[i] ] == 1) || (souse[i] < 0 && canFalse[ 0-souse[i] ] == 1) )
                cout << "Not defined\n";
            else if(souse[i] > 0 && canFalse[ souse[i] ] == 0 )
                cout << "Lie\n";
            else cout << "Truth\n";
        }
    }
    return 0;
}

C. Cipher 這個題,打死我我也想不出來啊!

題目大意:給出一個由26個小寫字母構成的字符串,現在對其進行任意次修改,修改的規則是相鄰兩個字母一個增加一,一個減少一。如bc可以變成ad or cb。

通過任意次修改之後,總共能產生多少個和自己不相同的字符串。

思路:首先要注意的是,這個結果只與兩個值有關:字符串的長度,每個字符的和。  證明我還是不會,但是可以想明白,首先可以得出的結論是,如果一個字符增加了1那麼任意一個其他的字符就得減1,注意這裏的是任意。也就是說,只要和相同,結果就相同。

很有意思!!

之後的問題就不難了!!

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define P 1000000007
long long dp[110][2700];

int main()
{
    memset(dp,0,sizeof(dp));
    for(int i=0;i<26;i++)
        dp[1][i]=1;
    for(int i=2;i<=100;i++)
    {
        for(int j=0;j<=2600;j++)
            for(int k=0;k<26;k++)
                dp[i][j+k]=(dp[i][j+k]+dp[i-1][j])%P;
    }
    int t;
    char ch[110];
    cin >> t;
    while(t--)
    {
        scanf("%s",ch);
        int len = strlen(ch);
        int sum = 0;
        for(int i = 0;i < len;i++)
            sum += ch[i]-'a';
        cout << (dp[len][sum]+P -1)%P << "\n";;
    }
    return 0;
}

D. Clues

很容易想到的是,把相連的圖縮成一個點。然後就是求生成樹的個數問題!

但是這個到底怎麼處理呢?、

我記得有這麼一個公式:Kn的生成樹個數爲:n^(n-2)

這個公式叫做Cayley公式。有一個有趣的證明,http://www.matrix67.com/blog/archives/682 其中用到了Prüfer編碼 

這個與那個不同的是,這個每一個點都是有好多個點縮成的,然後公式就有些變化,

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
#define N 100010
bool vis[N];

struct note
{
    int v,next;
}edge[N*3];
int head[N],kk;

void add(int from,int to)
{
    edge[kk].next = head[from];
    edge[kk].v = to;
    head[from] = kk++;
}
int cnt;
void dfs(int root)
{
    if(vis[root]) return ;
    cnt++;
    vis[root] = 1;
    for(int i = head[root];i != -1;i = edge[i].next)
        dfs(edge[i].v);
}
int main()
{
    int n,m,p;
    cin >> n >> m >> p;
    int a,b;
    kk = 1;memset(head,-1,sizeof(head));
    for(int i = 0;i < m;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);add(b,a);
    }
    memset(vis,0,sizeof(vis));
    long long sum = 0,re = 1;
    int k = 0;
    for(int i = 1;i <= n;i++)
    {
        if(vis[i] == 0)
        {
            cnt = 0;
            dfs(i);
            k++;
            sum = (sum + cnt)%p;
            re = (re * cnt)%p;
        }
    }
    for(int i = 1;i <= k-2;i++) re = (re * sum)%p;
    if(k == 1) cout << 1%p << "\n";
    else cout << re << "\n";
    return 0;
}

我個人感覺這套題目挺好的。

如果有不對的地方,歡迎交流。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章