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 的情况,显然此时每消除一个,都会有两个相同的元素合并,所以操作次数为 \(\lfloor \frac{n}{2} \rfloor + 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(n^2logn)\)
显然我们可以将 i 作为 \(a_i\) 的特征元素,
因为题目保证答案存在,所以也不需要考虑不合法情况,
如果 \(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 进行二进制拆分,然后分别考虑每一位的贡献,
比较特别的是,每一位的贡献不仅与当前位 \(c_i\) 有关,还与上一位 \(c_{i-1}\) 有关
- 当 \(c_{i-1}=0\), \(c_i=1\) 时,\((x,y)_i\) 只能是 \((1,1)\)
- 当 \(c_{i-1}=1\), \(c_i=0\) 时,\((x,y)_i\) 只能是 \((0,0)\)
- 当 \(c_{i-1}=0\), \(c_i=0\) 时,\((x,y)_i\) 可以为 \((0,0),(1,0),(0,1)\)
- 当 \(c_{i-1}=1\), \(c_i=1\) 时,\((x,y)_i\) 可以为 \((1,1),(1,0),(0,1)\)
(因为 \(c_{i-1}=1\) 所以上一位必有进位) - 特别的,我们规定 \(c_{-1}=0\),因为不可能有进位
所以当 \(c_{i-1}!=c_i\) 时,\((x,y)_i\) 取值只有1种可能,
当 \(c_{i-1}=c_i\) 时,\((x,y)_i\) 取值有3种可能
此时我们可以枚举二进制位分成多少01段,并且保证 1 的个数为 k,
这就回到了我们熟悉的组合计数
假设当前分成 q 段,那么就会有 \(\lceil \frac{q}{2} \rceil\) 段0串, \(\lfloor \frac{q}{2} \rfloor\) 段1串,(因为 \(c_{-1}=0\))
先考虑在 k 个 1 中插入0串,有 \(C_{k-1}^{\lceil \frac{q}{2} \rceil - 1}\) 种情况
然后考虑每一段0串分配多少个0,注意:加上 \(c_{-1}\) 有 \(n-k+1\) 个 0,有 \(C_{(n-k+1)-1}^{\lceil \frac{q}{2} \rceil - 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> >;
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;
}
标签:int,Pinely,rep,补题,using,Div,mod,ll,define
From: https://www.cnblogs.com/lunasama/p/16914778.html