Pinely Round 1 (Div. 1 + Div. 2)补题

Pinely Round 1 (Div. 1 + Div. 2)

A. Two Permutations

知识点:简单题
复杂度:O(1)

判断下 a,b 是否都等于 n,或者加起来是否小于 n-1 即可


#define rep(i,l,r) for(int i=l,_##i=r;i<=_##i;i++)
#define per(i,r,l) for(int i=r,_##i=l;i>=_##i;i--)
#define ll long long
#define fi first
#define se second
#define endl '\n'
#define pll pair<ll,ll>
#define pii pair<int,int>
template<class T> using vc = vector<T>;
template<class T> using vvc = vc<vc<T> >;
int n, a, b;

void solve()
{
    cin >> n >> a >> b;
    if ((a == n && b == n) || (a + b <= n - 2)) cout << "Yes" << endl;
    else cout << "No" << endl;
}

B. Elimination of a Ring

知识点:思维题
复杂度:O(n)

fst了,掉大分,呜呜呜,一开始猜了个错的结论,但是过了,就没想了

先判断元素种类不超过 2 的情况,显然此时每消除一个,都会有两个相同的元素合并,所以操作次数为 n2+1

如果元素种类大于 2,那么我们在不减少元素种类的前提下,先暴力删除左右两边元素不相同的元素,
因为元素种类大于 2,所以不会出现每个元素两边都相同的情况,
最后当某种元素只有 1 个时,就可以从该元素的一边删除所有元素,所以能操作 n 次


#define rep(i,l,r) for(int i=l,_##i=r;i<=_##i;i++)
#define per(i,r,l) for(int i=r,_##i=l;i>=_##i;i--)
#define ll long long
#define fi first
#define se second
#define endl '\n'
#define pll pair<ll,ll>
#define pii pair<int,int>
template<class T> using vc = vector<T>;
template<class T> using vvc = vc<vc<T> >;

int n, m, k;
void solve()
{
    cin >> n;
    vc<int> st(n + 1, 0);
    int cnt = 0;
    rep(i, 1, n)
    {
        int x; cin >> x;
        if (st[x]++ == 0) cnt++;
    }
    if (cnt <= 2) cout << n / 2 + 1 << endl;
    else cout << n << endl;
}

C. Set Construction

知识点:构造
复杂度:O(n2logn)

显然我们可以将 i 作为 ai 的特征元素,
因为题目保证答案存在,所以也不需要考虑不合法情况,
如果 b(i,j)=1 那么就让 i,j 连一条边
最后拓扑排序下,让每个父亲拥有儿子的所有元素即可


#define rep(i,l,r) for(int i=l,_##i=r;i<=_##i;i++)
#define per(i,r,l) for(int i=r,_##i=l;i>=_##i;i--)
#define ll long long
#define fi first
#define se second
#define endl '\n'
#define pll pair<ll,ll>
#define pii pair<int,int>
template<class T> using vc = vector<T>;
template<class T> using vvc = vc<vc<T> >;
const int N = 1e2 + 5;

int n, m, k;

char a[N][N];
vc<int> h[N], g[N];
set<int> da[N];
int d[N];

void solve()
{
    cin >> n;
    rep(i, 1, n) cin >> (a[i] + 1);
    rep(i, 1, n)
    {
        h[i].clear();
        g[i].clear();
        da[i].clear();
        d[i] = 0;
    }
    rep(i, 1, n) rep(j, 1, n)
    {
        if (a[i][j] == '1')
        {
            h[j].pb(i);
            g[i].pb(j);
            d[j]++;
        }
    }
    queue<int> q;
    rep(i, 1, n) if (d[i] == 0)
        q.push(i);
    rep(i, 1, n) da[i].insert(i);
    while (q.size())
    {
        int u = q.front(); q.pop();
        for (auto v : g[u]) if (--d[v] == 0) q.push(v);
        for (auto v : h[u]) da[u].insert(da[v].begin(), da[v].end());
    }
    rep(i, 1, n)
    {
        cout << da[i].size();
        for (auto x : da[i]) cout << ' ' << x;
        cout << endl;
    }
}

D. Carry Bit

知识点:dp
复杂度:O(n)

dp真的是我过不去的坎了,呜呜呜

官方题解已经说的很清楚了,
我们对 x,y 进行二进制拆分,然后分别考虑每一位的贡献,
比较特别的是,每一位的贡献不仅与当前位 ci 有关,还与上一位 ci1 有关

  • ci1=0, ci=1 时,(x,y)i 只能是 (1,1)
  • ci1=1, ci=0 时,(x,y)i 只能是 (0,0)
  • ci1=0, ci=0 时,(x,y)i 可以为 (0,0),(1,0),(0,1)
  • ci1=1, ci=1 时,(x,y)i 可以为 (1,1),(1,0),(0,1)
    (因为 ci1=1 所以上一位必有进位)
  • 特别的,我们规定 c1=0,因为不可能有进位

所以当 ci1!=ci 时,(x,y)i 取值只有1种可能,
ci1=ci 时,(x,y)i 取值有3种可能

此时我们可以枚举二进制位分成多少01段,并且保证 1 的个数为 k,
这就回到了我们熟悉的组合计数
假设当前分成 q 段,那么就会有 q2 段0串, q2 段1串,(因为 c1=0)
先考虑在 k 个 1 中插入0串,有 Ck1q21 种情况
然后考虑每一段0串分配多少个0,注意:加上 c1nk+1 个 0,有 C(nk+1)1q21


#define rep(i,l,r) for(int i=l,_##i=r;i<=_##i;i++)
#define per(i,r,l) for(int i=r,_##i=l;i>=_##i;i--)
#define ll long long
#define fi first
#define se second
#define endl '\n'
#define pll pair<ll,ll>
#define pii pair<int,int>
template<class T> using vc = vector<T>;
template<class T> using vvc = vc<vc<T> >;
const int mod = 1'000'000'007;
const int N = 1e6 + 5;

int n, m, k;

namespace cnm
{
    const int FN = 1e6 + 5;
    ll fac[FN];//阶乘数组
    ll ifc[FN];//阶乘逆元
    ll inv[FN];//逆元

    void init(int n)
    {
        fac[0] = fac[1] = ifc[0] = ifc[1] = inv[1] = 1;
        rep(i, 2, n)
        {
            fac[i] = fac[i - 1] * i % mod;
            inv[i] = (mod - mod / i) * inv[mod % i] % mod;
            ifc[i] = ifc[i - 1] * inv[i] % mod;
        }
    }
    
    ll C(ll n, ll m)
    {
        if (n < m || m < 0) return 0;
        return fac[n] * ifc[m] % mod * ifc[n - m] % mod;
    }
}
using cnm::C; using cnm::fac; using cnm::ifc; using cnm::inv;

ll q3[N];

void solve()
{
    cin >> n >> k;
    cnm::init(n);
    q3[0] = 1;
    rep(i, 1, n) q3[i] = q3[i - 1] * 3 % mod;
    ll ans(0);  
    if (!k) ans = q3[n];
    else
    {
        rep(i, 0, n)
        {
            ans += q3[n - i] * C(k - 1, (i + 1) / 2 - 1) % mod * C(n - k, i / 2) % mod;
            ans %= mod;
        }
    }
    cout << ans << endl;
}
posted @   Apricity_chen  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示