A.Circle
CF297E
场上秉持着正难反更难的精神,根本没考虑容斥。
正着统计合法方案很难,考虑用总方案数减去不合法方案数。
总方案数比较容易求得,为 \(\binom{n}{m}\) 。
不合法的可以归为两种情况:
- 一种是两边都与当前线段相离。
- 另一种是一个与当前线段相交,另一个相离。
第一种情况我们可以求出 \(l_i,r_i\) 分别代表这个线段左边和右边与之相离的线段数,那么当前线段答案为 \(l_i\times r_i\)。
与当前线段相交的线段为 \(n-l_i-r_i-1\),那么另一种情况就是 \((n-l_i-r_i-1)\times (l_i+r_i)\) ,由于两条线段相交,所以会算两次,最后除以二即可。
思路对了代码写的是真的快。
点击查看代码
#include <bits/stdc++.h>
#define fr first
#define se second
#define U unsigned
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define pLi pair<LL,int>
#define pLL pair<LL,LL>
#define __ __int128
#define ld long double
#define VE vector<LL>
#define db double
using namespace std;
inline int read()
{
int x = 0,f = 1;char ch = getchar();
while(!isdigit(ch)) (ch == '-') && (f = -1),ch = getchar();
while(isdigit(ch)) x = x*10+ch-48,ch = getchar();
return x*f;
}
const int N = 2e5+5;
int n,l[N],r[N];
struct Line{int l,r;}L[N];
struct BIT
{
int c[N];
inline void A(int i,int k){while(i <= n*2) c[i] += k,i += i&-i;}
inline int Q(int i){int res = 0;while(i) res += c[i],i -= i&-i;return res;}
inline void clear(){memset(c,0,sizeof(c));}
}t[3];
int main()
{
n = read();
for (int i = 1;i <= n;i++)
{
L[i] = {read(),read()};
if (L[i].l > L[i].r) swap(L[i].l,L[i].r);
}
sort(L+1,L+n+1,[](Line a,Line b){return a.r < b.r;});
for (int i = 1;i <= n;i++)
r[i] = i-1-t[0].Q(L[i].l),l[i] += t[1].Q(L[i].l-1),t[0].A(L[i].l,1),t[1].A(L[i].r,1);
t[0].clear();
for (int i = n;i >= 1;i--)
l[i] += n-i-t[0].Q(L[i].r)+t[0].Q(L[i].l-1),t[0].A(L[i].l,1);
LL ans = 1LL*n*(n-1)*(n-2)/6,sum = 0;
for (int i = 1;i <= n;i++)
ans -= 1LL*l[i]*r[i],sum += 1LL*(l[i]+r[i])*(n-l[i]-r[i]-1);
ans -= sum/2;
cout << ans;
return 0;
}
B.Stone
我不管,这就是困难 \(\text{dp}\) !!!
逆向考虑,由最终状态来求答案。
首先一段不与 \(1\) 相连的石子,它的方案数是固定的。
设 \(f_i\) 为只考虑一段连续 \(i\) 颗石子的方案数,枚举最后一个填上的石子 \(j\),则 \(f_i=\sum\limits_{j=1}^{i}(i-j+1)\binom{i-1}{j-1}f_{j-1}f_{i-j}\)
然后考虑与 \(1\) 相连的石子数,设 \(pre_{i,j}\) 为跟位置 \(1\) 连续的有 \(i−1\) 颗石子、并且已经失败了 \(j\) 次的方案数,则 \(pre_{i,j}=i\times pre_{i,j-1}+\sum\limits_{k=2}^{i}(i-k+1)\binom{i+j-2}{i-k}f_{i-k}\times pre_{k-1,j}\)。
再求后缀的方案数,设 \(suf_{i,j}\) 为从 \(i\) 到 \(n\) 有 \(j\) 颗石子的方案数,则 \(suf_{i,j}=\sum\limits_{k=0}^{j}\binom{j}{k}f_k\times suf_{i+k+1,j-k}\)。
最后我们的 \(ans=\sum\limits_{i=1}^{n}\binom{m}{i+p-1}pre_{i,p}\times suf_{i+2,m-p-i+1}\)。
复杂度 \(O(n^2p+nm^2)\)。
C.Coins
不会啊,但是 \(O(n^2)\) 暴力分好多。
CF1336C
牛魔忘了有时间复杂度 \(O(n^2)\) 的区间 \(dp\)。
感觉这种在开头或末尾填东西的好像好多都是区间 \(dp\),我猜的。
令 \(f_{l,r}\) 表示用 \(s\) 的前 \(r-l+1\) 个字符拼出\(t_{l...r}\)的方案数。
转移的话先枚举区间长度 \(len\) 和左端点 \(l\)。
- 当\(s_{len}=t_l,f_{l,r}\) 可以从 \(f_{l+1,r}\) 转移。
- 当\(s_{len}=t_r,f_{l,r}\) 可以从 \(f_{l,r-1}\) 转移。
注意如果字符串长度不同要给 \(t\) 补上通配符,初始化:若能 \(s_1\) 能匹配 \(t_i\) 则 \(f_{i,i} = 2\)。
CF1336D
自己想了个很精妙的构造方法结果是假的。
如果一个数 \(a_i>0\) ,那么仅一次查询就能知道具体数值,这点很重要。
首先用 \(2-1-3-1\) 把 \(a_1,a_2,a_3\) 都确定出来,首先 \(1\) 通过两次操作可以求出,先给 \(2\) 加一是为了能解出下面的方程来求出 \(2\),求出 \(2\) 的同时 \(3\) 也出来了。
\(\left\{\begin{matrix} bc=k_1\\b(c+1)=k_2\end{matrix}\right.\)
同时我们保证了一个重要的性质——\(a_1,a_2,a_3\) 都非零。
事实上有方法只需要四次就能确定 \(a_{1\dots4}\),但是由于没有仅是确定而没能保证非零,所以后面方程解不出来就寄掉了。
然后我们通过这几次询问可以确定 \(a_4\) 是否为零,而这个一旦确定了,那么我们仅需要一次查询就能知道 \(a_4\) 的具体数值了,同样对 \(4\) 进行询问时我们也能得知 \(5\) 是否为 \(0\),这样一直向后推,最后查询完 \(n-1\) 解方程求出 \(a_n\) 即可。