Codeforces 1068 - A/B/C/D/E - (Done)


鏈接:http://codeforces.com/contest/1068


A - Birthday - [計算題]

題意:一共 $N$ 種硬幣,我已經有其中 $K$ 種,我的 $M$ 個朋友每人送我等數量的硬幣,且送來的每一枚硬幣都不屬於同一種,要求最后我收到手上的硬幣至少有 $L$ 種是我沒有的,求每個人最少送幾枚硬幣。

題解:即求滿足 $K + L \le aM \le N$ 的最小正整數 $a$。

AC代碼:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
ll n,m,k,l;
int main()
{
    cin>>n>>m>>k>>l;
    if(m>n)
    {
        cout<<-1<<endl;
        return 0;
    }
    if(k+l<=m)
    {
        cout<<1<<endl;
        return 0;
    }
    ll a;
    if((k+l)%m==0) a=(k+l)/m;
    else a=(k+l)/m+1;
    if(a*m>n) cout<<-1<<endl;
    else cout<<a<<endl;
}

 


B - LCM - [求因數個數]

題意:給定正整數 $b(b \le 10^{10})$,對於 $1 \le a \le 10^{18}$,求 $\frac{{{\mathop{\rm lcm}\nolimits} (a,b)}}{a}$ 的不同取值個數。

題解:$\frac{{{\mathop{\rm lcm}\nolimits} (a,b)}}{a} = \frac{{ab}}{{a\gcd (a,b)}} = \frac{b}{{\gcd (a,b)}}$,即求 $b$ 的因數個數。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
int main()
{
    cin>>n;
    ll cnt=0;
    for(ll i=1;i*i<=n;i++)
    {
        if(n%i==0)
        {
            if(i*i==n) cnt++;
            else cnt+=2;
        }
    }
    cout<<cnt<<endl;
}

 


C - Colored Rooks - [構造題]

題意:

給定一個 $10^9 \times 10^9$ 的正方形網格,現有 $n$ 種顏色,給若干個棋子上色(每種顏色都要塗至少一個棋子),又給出 $m$ 個顏色對 $(x,y)$ 表示這兩個顏色是協調的

現在對於同一種顏色內的棋子集合,以及兩個和諧的顏色對構成的棋子並集,都要滿足連通性質,該性質的意思即:“首先規定棋子只可以走直線的任意距離,且可以完全不理睬非同集合內的棋子,但只有當它遇到同集合內的另一個棋子時才可以轉彎。而該集合中任意一個棋子,都它可以走到集合內的任意其他棋子的位置。”

現在你要給出任意一種可行的放置棋子的方案。

題解:

首先,第 $i$ 行全部給第 $i$ 種顏色,不得放其他顏色。為了防止某種顏色沒有塗棋子,可以先在 $(i,i)$ 位置放上顏色為 $i$ 的棋子。

然后對於給出的任意兩個協調顏色,依次在后面的 $n+1, n+2, \cdots$ 列里放上對應行數的兩枚棋子。

AC代碼:

#include<bits/stdc++.h>
using namespace std;

int n,m;
vector<int> ans[105];

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) ans[i].push_back(i);
    int col=n+1;
    for(int i=1,u,v;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        if(u==v) continue;
        ans[u].push_back(col);
        ans[v].push_back(col);
        col++;
    }
    for(int i=1;i<=n;i++)
    {
        printf("%d\n",ans[i].size());
        for(int k=0;k<ans[i].size();k++) printf("%d %d\n",i,ans[i][k]);
    }
}

 


D - Array Without Local Maximums - [dp]

題意:給定一個長度為 $n(n \le 1e5)$ 的數組 $a[1:n]$,$a[i]$ 的值域為 $1$ 到 $200$,且每個數的旁邊必須有一個不小於它的數。而有些數字被擦掉了,現在問共有多少種可行的填充方案。

題解:

看到這題第一感覺就dfs暴力搜索,然而時間復雜度顯然不行,因此考慮dp。

考慮 $dp[i][x][0,1,2]$ 的表示的狀態為已經確定了第 $i$ 個數字為 $x$,而 $0,1,2$ 分別表示第 $i-1$ 個數 $w$ 是小於、等於或大於 $x$。其存儲的值是其狀態下的方案數。

那么就有狀態轉移方程(當然這是建立在第 $i+1$ 位可以填 $y$ 的前提下的):

$\begin{array}{l} dp[i + 1][y][0] = \sum\limits_{x = 1}^{y - 1} {dp[i][x][0,1,2]} \\ dp[i + 1][y][1] = dp[i][y][0,1,2] \\ dp[i + 1][y][2] = \sum\limits_{x = y + 1}^{200} {dp[i][x][1,2]} \\ \end{array}$

邊界條件,考慮到第 $1$ 個數左邊是空的,相當於左邊是一個更小的數,因此有(依然是建立在第一位能填入 $x$ 的前提下):

$\begin{array}{l} dp[1][x][0] = 1 \\ dp[1][x][1] = 0 \\ dp[1][x][2] = 0 \\ \end{array}$

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=1e5+5;
int n,a[maxn];
ll sum,dp[maxn][203][3];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int x=1;x<=200;x++)
    {
        if(a[1]!=-1 && a[1]!=x) dp[1][x][0]=dp[1][x][1]=dp[1][x][2]=0;
        else dp[1][x][0]=1, dp[1][x][1]=dp[1][x][2]=0;
    }
    for(int i=2;i<=n;i++)
    {
        sum=0;
        for(int y=1;y<=200;y++)
        {
            if(a[i]!=-1 && a[i]!=y) dp[i][y][0]=0;
            else dp[i][y][0]=sum;
            sum+=(dp[i-1][y][0]+dp[i-1][y][1]+dp[i-1][y][2])%mod;
            sum%=mod;
        }

        for(int y=1;y<=200;y++)
        {
            if(a[i]!=-1 && a[i]!=y) dp[i][y][1]=0;
            else dp[i][y][1]=(dp[i-1][y][0]+dp[i-1][y][1]+dp[i-1][y][2])%mod;
        }

        sum=0;
        for(int y=200;y>=1;y--)
        {
            if(a[i]!=-1 && a[i]!=y) dp[i][y][2]=0;
            else dp[i][y][2]=sum;
            sum+=(dp[i-1][y][1]+dp[i-1][y][2])%mod;
            sum%=mod;
        }
    }
    ll ans=0;
    for(int x=1;x<=200;x++) ans+=(dp[n][x][1]+dp[n][x][2])%mod, ans%=mod;
    cout<<ans<<endl;
}

 


E - Multihedgehog - [BFS]

題意:

一個連通無向圖,若僅有一個節點度數不小於 $3$,其他所有節點度數均為 $1$,則稱為“刺蝟”。現在定義“$k$-刺蝟”,為:

  “$1$-刺蝟”即普通“刺蝟”;

  對於“$k$-刺蝟”,其由“$k-1$-刺蝟”變化而來,將“$k-1$-刺蝟”的所有度數為 $1$ 的頂點換成一個“$1$-刺蝟”的中心,即構成“$k$-刺蝟”。

現在給你一張圖和一個 $k$,讓你判斷這張圖是否為“$k$-刺蝟”。

題解:

首先,當 $k=11$ 時,節點數最少也需要 ${\sum_{i=0}^{11}{3^i}} = 265720$ 個頂點,顯然已經不夠了,所以對於 $k \ge 11$ 的情況可以直接判斷不行。

接下來,可以考慮以所有度數為零的節點為起始,將它們的深度定義為 $0$。然后自底向上地進行BFS(或者說BFS的一種變形?),同時不斷地刪除葉子結點。

對於每個節點,都需要判斷它的深度和度數是否可行,還要判斷其父親節點是否只有一個。

對於最后一個沒有父親節點的根節點,判斷他的深度是否等於 $k$。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=2e5+10;

int n,k;
int degree[maxn];

struct Edge{
    int u,v;
    int next;
};
Edge E[maxm];
int head[maxn],ne;
void init()
{
    ne=0;
    memset(head,0,sizeof(head));
}
void addedge(int u,int v)
{
    ++ne;
    E[ne].u=u, E[ne].v=v;
    E[ne].next=head[u];
    head[u]=ne;
}

int dist[maxn];
bool del[maxn],vis[maxn];
bool bfs()
{
    queue<int> Q;
    for(int i=1;i<=n;i++)
    {
        if(degree[i]==1) Q.push(i), vis[i]=1, dist[i]=0;
        else vis[i]=0;
    }
    memset(del,0,sizeof(del));
    while(!Q.empty())
    {
        int u=Q.front(); Q.pop();
        del[u]=1; //將節點刪除

        int cnt=0; //記錄父親節點個數
        for(int i=head[u];i;i=E[i].next)
        {
            int v=E[i].v;

            if(del[v]) continue;
            else cnt++;
            if(cnt>1) return false; //父親節點應當只有一個

            if(!vis[v])
            {
                vis[v]=1;
                dist[v]=dist[u]+1;
                Q.push(v);
            }
            else
            {
                if(dist[v]!=dist[u]+1) return false;
            }
        }

        if(cnt==0) { //當前節點是根節點
            if(degree[u]<3) return false;
            if(dist[u]!=k) return false;
        }
        else if(degree[u]>1) { //當前節點不是根節點也不是葉子結點
            if(degree[u]<=3) return false;
        }
    }
    return true;
}

int main()
{
    cin>>n>>k;
    init();
    memset(degree,0,sizeof(degree));
    for(int i=1,u,v;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
        degree[u]++;
        degree[v]++;
    }
    if(n<4 || k>=11) printf("No\n");
    else printf("%s\n",bfs()?"Yes":"No");
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM