Codeforces 1072 - A/B/C/D - (Done)

連接:http://codeforces.com/contest/1072/ios


A - Golden Plate - [計算題]

#include<bits/stdc++.h>
using namespace std;
inline int calc(int w,int h){return (w+h-2)*2;}
int w,h,k;
int ans;
int main()
{
    cin>>w>>h>>k;
    for(;w&&h&&k;w-=4,h-=4,k--) ans+=calc(w,h);
    cout<<ans<<endl;
}

 


B - Curiosity Has No Limits - [DFS]

對於常數 $C_1,C_2$ 和變量 $x,y$ 的方程組:c++

$\left\{ {\begin{array}{*{20}c} {C_1 = x|y} \\ {C_2 = x\& y} \\ \end{array}} \right.$數組

除了 $x$ 和 $y$ 之間能互換一下以外,其實解是惟一的。spa

所以,說是從 $1$ 到 $n$ 的深搜,其實只是 $O(n)$ 的枚舉,由於當你肯定了第一個數字 $t[1]$ 以後,後面的跟着都是肯定的,所以只會DFS只會跑一條深度爲 $n$ 的鏈。code

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=1e5+50;

int n;
pii a[maxn],b[maxn];
pii cho[4];
bool judge(pii a,pii b,pii x,pii y)
{
    if((x.first|y.first)!=a.first || (x.second|y.second)!=a.second) return 0;
    if((x.first&y.first)!=b.first || (x.second&y.second)!=b.second) return 0;
    return 1;
}

bool ok;
int c[maxn];
void dfs(int d,int p)
{
    if(ok) return;
    if(d==n+1)
    {
        ok=1;
        return;
    }
    for(int i=0;i<=3;i++)
    {
        if(judge(a[d-1],b[d-1],cho[p],cho[i]))
        {
            c[d]=i;
            dfs(d+1,i);
        }
    }
}

int main()
{
    cho[0]=make_pair(0,0);
    cho[1]=make_pair(0,1);
    cho[2]=make_pair(1,0);
    cho[3]=make_pair(1,1);
    cin>>n;
    for(int i=1,k;i<n;i++)
    {
        scanf("%d",&k);
        a[i].first=k/2;
        a[i].second=k%2;
    }
    for(int i=1,k;i<n;i++)
    {
        scanf("%d",&k);
        b[i].first=k/2;
        b[i].second=k%2;
    }

    ok=0;
    for(int i=0;i<=3;i++)
    {
        c[1]=i;
        dfs(2,i);
        if(ok) break;
    }
    if(ok)
    {
        printf("YES\n");
        for(int i=1;i<=n;i++) printf("%d ",c[i]);
        printf("\n");
    }
    else printf("NO\n");
}

 


C - Cram Time - [暴力]

(忍不住想說,我隊友太強了,跟他組隊是我拖後腿了55555)blog

顯然,要放最多的數進去,確定是放 $1 \sim n$,其中 $n$ 是知足 $\frac{{\left( {n + 1} \right)n}}{2} \le a + b$ 的最大整數。隊列

考慮第一天看 $a$ 的書,咱們從最大的 $n$ 枚舉起,遇到能塞得下的就往裏塞,這樣必然可讓第一天的 $a$ 個小時被佔滿,ci

而剩下的所有放到次日就好了,剩下的那些加起來必然不會超過 $b$ 小時。字符串

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=63300;

ll a,b;
ll n;
bool vis[maxn];

int main()
{
    cin>>a>>b;
    for(n=0;n<maxn;n++) if((n+1)*n/2<=a+b && (n+2)*(n+1)/2>a+b) break;

    memset(vis,0,sizeof(vis));
    int cnt=0;
    for(int i=n;i>=1;i--)
    {
        if(a>=i)
        {
            vis[i]=1;
            a-=i;
            cnt++;
        }
    }

    printf("%d\n",cnt);
    for(int i=1;i<=n;i++) if(vis[i]) printf("%d ",i);
    printf("\n");
    printf("%d\n",n-cnt);
    for(int i=1;i<=n;i++) if(!vis[i]) printf("%d ",i);
    printf("\n");
}

 


D - Minimum path - [BFS]

題意:get

給出存儲小寫字母的 $n \times n$ 的矩陣,規定每次只能往下跑一格或者往右跑一個,要從左上角的 $(1,1)$ 跑到右下角 $(n,n)$,問路徑上產生的字符串字典序最小是哪一個(另外, 你有 $k$ 次機會可以修改某個字母爲任意一個字母)。

題解:

按照反對角線,從第 $1$ 層的 $(1,1)$ 跑到第 $2 \times n - 1$ 層的 $(n,n)$,構建兩個隊列(數組模擬)q[0] 和 q[1],

隊列裏面存儲一個Node結構體,Node結構體中存儲:目前我走到的了 $(i,j)$,給相應路徑上產生字符 $c$,接下來我還有多少次 $k$ 能用。

一、從當前層下一層BFS,從當前 q[f] 隊列(其中 f = 0 or 1)取出節點,最多有 $O(n)$ 個節點。

二、經過這個節點計算出它下一層可能會走到的節點,入隊 q[f^1]。

三、同時,在入隊時,咱們要把全部能去重的全都去重(就是當前層的兩格 $(i+1,j)$ 和 $(i,j+1)$ 都走到下一層的 $(i+1,j+1)$,這種狀況只須要判斷一下哪一個更優便可,顯然是字符越小的越優,若是字符相同,那麼確定是 $k$ 越大越優);

四、另外,咱們用 $mini$ 變量記錄 q[f^1] 隊列中全部元素裏字典序最小的字符(這個字符就是要求輸出的字符串中第 $k$ 個位置上的字符),而對於 q[f^1] 中大於 $mini$ 的字符的元素,通通均可以去掉(用vis數組標記掉),若是處理完髮現 q[f^1] 隊列已經空了,就跳出BFS;不然就清空 q[f] 隊列,而後令 f^=1,回到步驟 1 繼續。

時間複雜度:

BFS一共前進 $O(n)$ 層,每層要遍歷一遍當前隊列取出當前節點,而隊列中元素不超過 $O(n)$,同時產生的下個隊列內元素同樣不會超過 $O(n)$,所以時間複雜度爲 $O(n^2)$。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2100;

int n,k;
char mp[maxn][maxn];
vector<char> ans;

struct Node{
    char c;
    int i,j;
    int k;
    Node(){}
    Node(char _c,int _i,int _j,int _k){c=_c,i=_i,j=_j,k=_k;}
    bool operator<(const Node& oth)const
    {
        if(c==oth.c) return k>oth.k;
        else return c<oth.c;
    }
};

int tot[2];
Node q[2][2*maxn];
int vis[maxn][maxn];
const int dx[2]={0,1},dy[2]={1,0};
inline bool in(int i,int j){return (1<=i && i<=n && 1<=j && j<=n);}
void bfs()
{
    tot[0]=0;
    tot[1]=0;
    memset(vis,-1,sizeof(vis));

    if(mp[1][1]=='a') q[0][tot[0]++]=Node('a',1,1,k);
    else q[0][tot[0]++]=Node(k?'a':mp[1][1],1,1,max(0,k-1));
    ans.push_back(q[0][0].c);
    vis[1][1]=0;

    int f=0;
    Node now,nxt;
    while(tot[f])
    {
        int mini=(int)('z'+10);
        for(int i=0;i<tot[f];i++)
        {
            now=q[f][i];
            if(vis[now.i][now.j]==-1) continue;
            for(int z=0;z<=1;z++)
            {
                int x=now.i+dx[z], y=now.j+dy[z];
                if(!in(x,y)) continue;

                if(mp[x][y]=='a') nxt=Node('a',x,y,now.k);
                else nxt=Node(now.k?'a':mp[x][y],x,y,max(0,now.k-1));
                if(vis[x][y]==-1)
                {
                    vis[x][y]=tot[f^1];
                    q[f^1][tot[f^1]++]=nxt;
                    mini=min(mini,(int)nxt.c);
                }
                else
                {
                    Node &tmp=q[f^1][(vis[x][y])];
                    if(nxt<tmp) tmp=nxt, mini=min(mini,(int)nxt.c);
                }
            }
        }

        if(mini<(int)('z'+10)) ans.push_back((char)mini);
        else break;

        for(int i=0;i<tot[f^1];i++)
        {
            nxt=q[f^1][i];
            if((int)nxt.c>mini) vis[nxt.i][nxt.j]=-1;
        }

        tot[f]=0;
        f^=1;
    }
}

int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);

    if(k+1>=n+n)
    {
        for(int i=1;i<=2*n-1;i++) printf("a");
        printf("\n");
        return 0;
    }

    ans.clear();
    bfs();
    for(int i=0;i<ans.size();i++) printf("%c",ans[i]);
    printf("\n");
}
相關文章
相關標籤/搜索