Codeforces 1068 - A/B/C/D/E - (待补)

链接: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 - (待补)

猜你喜欢

转载自www.cnblogs.com/dilthey/p/9853026.html