开始刷题了
CF 605 C Freelancer's Dreams
题目
给个矩阵
[mathbf{A}=egin{pmatrix} a_1& a_2 & cdots & a_n \ b_1& b_2 & cdots & b_nend{pmatrix}]
求一个矩阵
[mathbf{x}=egin{pmatrix} x_1 &x_2 & cdots & x_nend{pmatrix}^mathrm{T}]
最小化[sum_{i=1}^n x_i]
使[mathbf{Ax}geqslantegin{pmatrix}p&qend{pmatrix}^mathrm{T}]
求最小化的值
解
一眼看过去像是线性规划,可是我不会,看评论可以转化为对偶形式用对偶单纯形算法,发现是凸的然后三分,可是我还是不会
原来的不等式可以写成
[egin{cases}a_1 x_1+a_2x_2+cdots+a_nx_ngeqslant p\b_1 x_1+b_2x_2+cdots+b_nx_ngeqslant q\end{cases}]
加两个松弛变量
[egin{cases}a_1 x_1+a_2x_2+cdots+a_nx_n-t_1= p\b_1 x_1+b_2x_2+cdots+b_nx_n-t_2=q\t_1geqslant 0,;t_2geqslant 0end{cases}]
变个形状
[egin{cases}mathrm{ans} imes(a_1 x_1'+a_2x_2'+cdots+a_nx_n')-t_1= p\mathrm{ans} imes(b_1 x_1'+b_2x_2'+cdots+b_nx_n')-t_2=q\t_1geqslant 0,;t_2geqslant 0\x_1'+x_2'+cdots+x_n'=1end{cases}]
如果把$(a_i,b_i)$看成平面上的点,那么括号里面的内容就相当于这些点形成的凸包的坐标值(可以简单证明……只需要证出三角形的情况,剩下用三角剖分就可以了)
再进一步,把$t_1$和$t_2$移到括号内
[egin{cases}mathrm{ans} imes(a_1 x_1'+a_2x_2'+cdots+a_nx_n'-t_1')= p\mathrm{ans} imes(b_1 x_1'+b_2x_2'+cdots+b_nx_n'-t_2')=q\t_1geqslant 0,;t_2geqslant 0\x_1'+x_2'+cdots+x_n'=1end{cases}]
相当于原来的凸包一直向下和向左延伸
这个区域就相当于ans=1时能走的范围。为了让ans最小,很容易发现需要选择上凸包和OP的交点。
CF 615 D Multipliers
题目
给你一些质数,求这些质数的积的所有因子的积
解
观察数字x的因子,$k$和$x/k$成对出现,答案就是$x^{frac{d(x)}{2}}$
有了这个就很容易推了
牛客挑战赛46 排列
题目
给一个排列,长度500
超级逆序对的定义:满足 $i<j$ 且 $a_i>a_j+1$ 的二元组 $(i,j)$ 。
知道了这个排列的长度和超级逆序对个数(500以内),求猜中这个排列的概率。
解
比赛的时候看到概率就放弃了……其实不用那么慌张,因为概率就是所有这样的排列个数的倒数
类似于向排列中插入更大的数字,形成一个新的排列,那么dp就可以了,需要注意一下优化。(列方程到写代码用了不同的字母,自己把自己绕晕了……)
#include<iostream> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int MO=998244353; const int MAXN=507; int dp[2][MAXN][MAXN]; int s[2][MAXN][MAXN]; inline int qpow(int a, int b) { int ans=1; for(; b; b>>=1) { if(b&1) ans=1ll*ans*a%MO; a=1ll*a*a%MO; } return ans; } int main() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n,K; cin >> n >> K; memset(dp,0,sizeof dp); memset(s,0,sizeof s); int z=1; dp[0][0][0]=1; s[0][0][0]=1; for(int i=2; i<=n; i++, z^=1) { for(int k=0; k<=K; k++) { s[z][0][k]=0; for(int j=0; j<i; j++) { dp[z][j][k]=0; if(j>=1 && k-i+1+j>=0) dp[z][j][k]=(dp[z][j][k]+s[z^1][j-1][k-i+1+j])%MO; if(k-i+1+j+1>=0) dp[z][j][k]=((dp[z][j][k]+s[z^1][i-2][k-i+1+j+1])%MO-(j>=1?s[z^1][j-1][k-i+1+j+1]:0)+MO)%MO; s[z][j][k]=(dp[z][j][k]+(j?s[z][j-1][k]:0))%MO; } } } int ans=qpow(s[z^1][n-1][K],MO-2); cout << ans << endl; }