不要停止演奏,就算你的身体已如碎肉一般亦是如此。
线性代数在 oi 中的应用 重庆市巴蜀中学 郭雨豪
摘要:线性代数在 oi 中没有用。
动点(point)
首先考虑不带修。这显然,线段树维护矩阵乘。
然后把修改加上。修改看起来每个矩阵都要乘一下,没法修改。但是我们不考虑矩阵,直接改坐标系。
对于平移,把点先逆向平移,做完操作之后再正向平移回来。对称同理,但是对称之后旋转方向要变一下。旋转维护一个逆时针一个顺时针矩阵就行了。
没写。
有限域方阵期望对数转置相关度(transpose)
线性代数。sb。
关于题目背景:我们都知道怎么求特征多项式。不知道的右转洛谷模板题解。
首先满足 \(AB=A^T\) 的矩阵 \(A\) 需要满足行向量集和列向量集相等(这是结论)。那我们枚举这些向量 \(C\) ,那么设 \(A\) 的秩为 \(r\),\(A\) 就可以表示为 \(A=C^TMC\),其中 \(C\) 为 \(n\times r\) 满秩矩阵, \(M\) 为 \(r\times r\) 满秩矩阵。它的方案数显然是
\[\begin{bmatrix}n\\r\end{bmatrix}_p\prod_{i=0}^{r-1}p^r-p^i=\begin{bmatrix}n\\r\end{bmatrix}_p(p^r)^r\prod_{i=1}^r1-p^{-i} \]然后考虑 \(R_{\log}(A)\) 是多少。对于矩阵 \(A\),我们计算 \(B\) 的个数。首先一组向量的方案数是 \(p^n\),有 \(n-r\) 组可以随意定,那么 \(R(A)=p^{n(n-r)}\),即得到 \(R_{\log}(A)=n(n-r)+1\)。那这两个卷积一下就行了。
sb 任意模数。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const long double pi=acos(-1);
const int sq=(1<<15)-1;
struct cp{
long double r,i;
cp(long double a=0,long double b=0){r=a;i=b;}
cp operator+(const cp &s)const{return cp{r+s.r,i+s.i};}
cp operator-(const cp &s)const{return cp{r-s.r,i-s.i};}
cp operator*(const cp &s)const{return cp{r*s.r-i*s.i,r*s.i+i*s.r};}
}a[300010],b[300010],p[300010],q[300010];
int n,m,P,mod,wl=1,r[300010],ans[300010],a1[300010],b1[300010],f[300010],last[300010];
void get(int n){
while(n>=wl)wl<<=1;
for(int i=0;i<=wl;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(__lg(wl)-1));
}
void fft(cp a[],int n,int tp){
for(int i=1;i<n;i++)if(i<r[i])swap(a[i],a[r[i]]);
for(int mid=1;mid<n;mid<<=1){
cp wn={cos(pi/mid),tp*sin(pi/mid)};
for(int j=0;j<n;j+=mid<<1){
cp w={1,0};
for(int k=0;k<mid;k++,w=w*wn){
cp x=a[j+k],y=w*a[j+mid+k];
a[j+k]=x+y;a[j+mid+k]=x-y;
}
}
}
if(tp^1)for(int i=0;i<n;i++)a[i].r/=n,a[i].i/=n;
}
void mul(int n,int a1[],int b1[],int c[]){
for(int i=0;i<=n;i++)a[i]=cp (a1[i]&sq,a1[i]>>15);
for(int i=0;i<=n;i++)b[i]=cp (b1[i]&sq,b1[i]>>15);
fft(a,wl,1);fft(b,wl,1);
for(int i=0;i<wl;i++){
int ret=(wl-i)&(wl-1);
p[i]=(cp){0.5*(a[i].r+a[ret].r),0.5*(a[i].i-a[ret].i)}*b[i];
q[i]=(cp){0.5*(a[i].i+a[ret].i),0.5*(a[ret].r-a[i].r)}*b[i];
}
fft(p,wl,-1);fft(q,wl,-1);
for(int i=0;i<wl;i++){
long long p1=p[i].r+0.5,q1=p[i].i+0.5,x=q[i].r+0.5,y=q[i].i+0.5;
c[i]=(p1%mod+((q1+x)%mod<<15)+((y%mod)<<30))%mod;
}
}
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
int jc[300010],inv[300010];
int main(){
scanf("%d%d%d",&n,&P,&mod);
jc[0]=inv[0]=1;
int ret=1;
for(int i=1;i<=n;i++){
ret=1ll*ret*P%mod;
jc[i]=1ll*jc[i-1]*(1-ret+mod)%mod;
inv[i]=qpow(jc[i],mod-2);
}
int Iv=qpow(P,mod-2);ret=1;f[0]=1;
for(int i=1;i<=n;i++){
ret=1ll*ret*Iv%mod;
f[i]=1ll*f[i-1]*(1-ret+mod)%mod;
}
for(int i=1;i<=n;i++)f[i]=1ll*f[i]*qpow(P,1ll*i*i%(mod-1))%mod*inv[i]%mod;
for(int i=0;i<=n;i++)a1[i]=f[i];
for(int j=0;j<=n;j++)b1[j]=1ll*inv[j]*j%mod;
get(n+1<<1);
mul(wl,a1,b1,ans);
for(int i=1;i<=n;i++)last[i]=1ll*ans[i]*i%mod;
memset(a1,0,sizeof(a1));memset(b1,0,sizeof(b1));memset(ans,0,sizeof(ans));
memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(p,0,sizeof(p));memset(q,0,sizeof(q));
for(int i=0;i<=n;i++)a1[i]=f[i];
for(int j=0;j<=n;j++)b1[j]=inv[j];
mul(wl,a1,b1,ans);
for(int i=1;i<=n;i++){
last[i]=1ll*(last[i]+ans[i])%mod*jc[i]%mod;
printf("%d\n",last[i]);
}
return 0;
}
灭国(destroy)
贪心。
首先不加边的话就是把拓扑排序的队列变成小根堆。考虑加边怎么做。
首先我们肯定是越大越好,那么拓扑排序的时候把当前所有能到达的点找个最大的作为当前点,剩下的放到另一个堆。如果当前的堆为空,则把另一个堆里的最大值扔过来,并给他从当前拓扑序最后的点连一条边。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <map>
using namespace std;
int n,m,k,d[100010];
set<int>s,s0;
map<int,int>mp[100010];
vector<int>g[100010];
int cnt,ans[100010];
struct stu{
int u,v;
}eg[100010];
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
g[u].push_back(v);d[v]++;mp[u][v]=1;
}
for(int i=1;i<=n;i++)sort(g[i].begin(),g[i].end());
for(int i=1;i<=n;i++)if(!d[i])s.insert(i);
while(k&&!s.empty()){
s0.insert(*s.begin());s.erase(s.begin());
k--;
}
int pos=0;
for(int i=1;i<=n;i++){
if(s.empty()){
int x=*prev(s0.end());
s0.erase(x);s.insert(x);
if(!pos||mp[pos].find(x)!=mp[pos].end())k++;
else eg[++cnt]={pos,x};
}
int x=*s.begin();s.erase(x);
ans[++ans[0]]=x;
for(int v:g[x]){
d[v]--;
if(!d[v]){
if(k)s0.insert(v),k--;
else s.insert(v);
}
}
pos=x;
}
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
printf("\n%d\n",cnt);
for(int i=1;i<=cnt;i++)printf("%d %d\n",eg[i].u,eg[i].v);
return 0;
}
然而比起题目来说感觉更值得一说的是题目背景。
\[\varlimsup_{n\to\infty}\left(\frac{1+a^{n+1}}{a_n}\right)^n\ge e \]请证明:对于任意正项序列 \(\{a_n\}\),有
并且这个估计是最好的。
这是卓里奇《数学分析》第三章第二节的习题 11。
看起来这个和 \(\lim_{n\to\infty}(1+\dfrac 1n)^n=e\) 长的差不太多,于是右边代替。同时左边是上极限,于是只要证明有子列满足。即可化简两侧:
\[\left(\frac{1+a_{n+1}}{a_n}\right)^n\ge\lim_{n\to\infty}(1+\dfrac 1n)^n \]\[n\left(\frac{1+a_{n+1}}{a_n}-1\right)\ge 1 \]反证。如果不成立,则恒有
\[n\left(\frac{1+a_{n+1}}{a_n}-1\right)<1 \]\[\frac 1{n+1}+\frac{a_{n+1}}{n+1}<\frac{a_n}n \]从而得到
\[\sum_{i=1}^n\frac 1i+\frac{a_n}n<a_1+1 \]当 \(n\to\infty\) 时
\[\sum_{n=1}\frac 1n+\varlimsup_{n\to\infty}\frac{a_n}n\le a_1+1 \]显然是错的。于是得证。
标签:infty,frac,省选,矩阵,int,联测,100010,武汉,include From: https://www.cnblogs.com/gtm1514/p/17234071.html