1. 程式人生 > >Codeforces Round #472 A-D

Codeforces Round #472 A-D

A. Tritonic Iridescence

題意:使用CMY對字串進行填充,要求相鄰的兩個不能相同,如果有兩種以上可行填充方法就輸出“YES”否則輸出“NO”。

思路:對每一個問號進行判定,最後的結果就是所有問號的可行方案數的乘積,當然可能會超出資料範圍,因此只要大於2不再變大。此外, 還要判斷是否有連續兩個相同。

AC程式碼:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;

const int MAXN = 105;
const int MOD = 1e9+7;
const int INF = 1e9+7;

char str[MAXN];
set<char> gg;
int n;

int main()
{
    //FSIO;
    while(cin>>n)
    {
        scanf(" %s",str+1);
        int flag = 0;
        int res = 0;
        for(int i=1;i<=n;++i)
        {
            if(str[i]=='?')
            {
                if(!res)    res=1;
                gg.clear();
                if(i>1&&str[i-1]!='?') gg.insert(str[i-1]);
                if(i<n&&str[i+1]!='?') gg.insert(str[i+1]);
                if(res>=2)  res = 3;
                else    res = res*(3-gg.size());
            }
            else if(i<n&&str[i]==str[i+1])   {flag=1; break;}
        }
        if(!flag&&res>=2) cout<<"Yes"<<endl;
        else    cout<<"No"<<endl;
    }
    return 0;
}

B. Mystical Mosaic

題意:給定一種操作,即對於某非空的正整數集合的集合R,C,對於R_i和C_i,填充網格中R_i行與C_i列相交點為黑色,且R和C中任意兩集合互斥。對於某網格,如能從空白網格經這樣的操作變成該網格則輸出“Yes”,否則輸出“No”。

思路:因為每一個點都要進行判定,不妨從左上角開始掃描,對於存在黑格的行進行掃描,取其中的所有為黑格的對應列,再對所有列往下逐行掃描,若這些列在某行存在黑格,則所有列都必須有才行。之後標記已經掃描過的行列以及格子,只要遇到已經標記的行列就不行,否則則行。

AC程式碼:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;

const int MAXN = 55;
const int MOD = 1e9+7;
const int INF = 1e9+7;

char mapp[MAXN][MAXN];
int mkr[MAXN];
int mkc[MAXN];


int n, m;
int cntblack;

int walk(int x, int y)
{
    vector<int> tmpp;
    for(int t=y; t<=m; ++t)
        if(mapp[x][t]=='#')
        {
            if(!mkc[t])
            {
                mkc[t] = 1;
                mapp[x][t]='.';
                cntblack--;
                tmpp.push_back(t);
            }
            else    return 0;
        }


    vector<int> tomark;

    for(int j=x+1; j<=n; ++j)
    {
        int cnt = 0;
        for(int i=0;i<tmpp.size();++i)
        {
            if(mapp[j][tmpp[i]]=='#')
            {
                cnt++;
                if(!mkr[j])
                {
                    tomark.push_back(j);
                    mapp[j][tmpp[i]]='.';
                    cntblack--;
                }
                else    return 0;
            }
        }
        if(cnt&&cnt!=tmpp.size())    return 0;
    }
    for(int i=0; i<tomark.size(); ++i)
        mkr[tomark[i]] = 1;
    return 1;
}

int solve()
{
    memset(mkr,0,sizeof(mkr));
    memset(mkc,0,sizeof(mkc));
    for(int i=1; i<=n; ++i)
    {
        for(int j=1; j<=m; ++j)
        {
            if(mapp[i][j]=='#')
            {
                if(!mkr[i]&&!mkc[j])
                {
                    if(!walk(i,j))     return 0;
                }
                else    return 0;
                /*cout<<endl;
                for(int mi=1;mi<=n;++mi)
                {
                    for(int mj=1;mj<=m;++mj)
                        cout<<mapp[mi][mj];
                    cout<<endl;
                }*/
            }
        }
    }
    return 1;
}

int main()
{
    FSIO;
    while(cin>>n>>m)
    {
        cntblack = 0;
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=m; ++j)
            {
                cin>>mapp[i][j];
                if(mapp[i][j]=='#')
                    cntblack++;
            }
        if(solve()&&cntblack==0) cout<<"Yes"<<endl;
        else    cout<<"No"<<endl;
    }
    return 0;
}

C. Three-level Laser

題意:在含n個數字的升序序列E中,依次選擇三個下標i,j,k,使得i<j<k,且E_i + U<=E_k,輸出最大的(E_k - E_j) / (E_k - E_i)。

思路:對於某個E_i來說,要使得該商最大,j肯定為i+1,而k肯定是滿足要求的最大下標。所以對序列E進行一次掃描判斷每個i的最大對應k即可。最後遍歷一遍E求最大該商。

AC程式碼如下:

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;

const int MAXN = 100005;
const int MOD = 1e9+7;
const int INF = 1e9+7;

int n, U;
int engery[MAXN];
int matters[MAXN];

int main()
{
    //FSIO;
    while(scanf("%d%d",&n,&U)!=EOF)
    {
        for(int i=1;i<=n;++i)   scanf("%d",engery+i);
        double ans = -1;
        int cur = 1;
        memset(matters,-1,sizeof(matters));
        for(int i=1;i<=n;++i)
        {
            while(engery[i]-U>engery[cur]&&cur<=n)
            {
                matters[cur] = i-1;
                cur++;
            }
        }
        for(;cur<=n;++cur)  matters[cur] = n;
        /*for(int i=1;i<=n;++i)
            cout<<matters[i]<<" ";
        cout<<endl;*/
        for(int i=1;i+2<=n;++i)
        {
            if(matters[i]>i+1)
            {
                ans = max(ans, (double)(engery[matters[i]]-engery[i+1])/(double)(engery[matters[i]]-engery[i]));
            }
        }
        printf("%.10f\n",ans);
    }
    return 0;
}

D. Riverside Curio

題意:主角每天對河流水位進行標記,相同水位不重複標記。給定每天的在河流水位上的標記數,求最小的所有天的河流水位下的標記數之和。

思路:對於某天來說,水位下的標記數 = 總的標記數 - 1 - 河流水位上的標記數。

所以,只需要求最小的每天的標記數即可。而對於某天在水位上的標記數來說,總的標記數的最小值即該數 + 1,而相鄰兩天的標記總數最多加一個。所以只需按照上述規則進行貪心地求每天的最小標記數即可,最後對相鄰兩天差大於1的進行貪心地處理(即順次遞減)。最後遍歷陣列求和即可。

AC程式碼如下:

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <string>
#include <vector>
#include <set>

using namespace std;

#define FSIO  ios::sync_with_stdio(0);cin.tie(0);
#define DEBUG(a)   cout<<"DEBUG: "<<(a)<<endl;

const int MAXN = 100005;
const int MOD = 1e9+7;
const int INF = 1e9+7;

long long level[MAXN];
long long minlevel[MAXN];
long long n;

int main()
{
    FSIO;
    while(cin>>n)
    {
        for(long long i=1;i<=n;++i)
            cin>>level[i];
        minlevel[1] = 1;
        for(long long i=2;i<=n;++i)
        {
            if(minlevel[i-1]-1>=level[i])   minlevel[i] = minlevel[i-1];
            else
            {
                long long tmp = 1;
                while(minlevel[i-1]-1+tmp<level[i]) tmp++;
                minlevel[i] = minlevel[i-1]+tmp;
                for(long long j=0;j<tmp;++j)
                    minlevel[i-j] = minlevel[i]-j;
            }
        }
        for(int i=n;i>1;--i)
        {
            if(minlevel[i]-minlevel[i-1]>1)
                minlevel[i-1] = minlevel[i]-1;
        }
        /*for(long long i=1;i<=n;++i)
            cout<<minlevel[i]<<" ";
        cout<<endl;*/
        long long ans = 0;
        for(long long i=1;i<=n;++i)
            ans = ans + (minlevel[i]-1-level[i]);
        cout<<ans<<endl;
    }
    return 0;
}