4.11省选练习
随笔
今天写了写成人礼给自己的一封信,自己也要成人了啊,挺感慨的
今晚有一个总结会,被一堆人奶了
觉得(原)数学老师(数竞教练)说的挺对的,最后几天,心态平稳最重要,要不急不躁,每一天都努力,期待每一种结果,那么最后肯定不会很差
被$XJJ$(小吉吉)奶了一口,提到了$Varuxn,$话说一个挺强的人退役也很可惜的
为了自己,为了对我抱有期待的人,当然是要拼尽全力了
\(T1\)
\(emm,\)一顿操作把我秀到了
\(n<=1000,k<=20\)
\((AB)^k\)
\(A(n\times k)\times B(k\times n)=C(n\times n)\)
\(B(k\times n)\times A(n\times k)=C(k\times k)\)
嗯,很\(nb\)
\((AB)^k=A(BA)^{k-1}B\)
我们要维护\(G(i)=(i-1)^3\times C^i=(i^3-3i^2+3i-1)C^i\)
我们要分别维护出来
我们考虑三次项系数
\(k^3C_k=(i+j)^3C_iC_j=(i^3+3i^2j+3ij^2+j^3)C_i\times C_j\)
暴力展开合并即可
然后对于前缀和,我们只需要维护所有的\(2^i\)然后倍增时候顺便维护一下就好了
矩阵前缀和直接把矩阵扩大一倍即可
\(T2\)
一想到连通性,肯定是并查集吧
考虑维护原图连通性会很麻烦,记得外出集训一道考试题使用并查集维护有没有一条链直接给横着断开了,那么这个也一样,就是看有没有一个链中间劈开就好了
当然有一个很套路的\(trick,\)断环为链,然后复制一遍,那么在两边维护同一个并查集,看看有没有长度大于等于\(n\)的链就好了
#include
using namespace std;
#define MAXM 600005
#define MAXN 3005
const int S=600001,T=600002;
int n,m,Q,fa[MAXM],a[MAXN][MAXN<<1],cnt,ans,u[10],v[10];
int dy[10]={1,1,1,0,0,-1,-1,-1};
int dx[10]={-1,1,0,-1,1,-1,1,0};
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main()
{
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d%d",&n,&m,&Q);
int lm=m<<1;
fa[S]=S;fa[T]=T;
for(int i=1;i<=n;i++)a[i][0]=S,a[i][lm+1]=T;
while(Q--)
{
int x,y,lu=0,lv=0;
scanf("%d%d",&x,&y);
if(a[x][y])continue;
int flag1s=0,flag2s=0,flag1t=0,flag2t=0;
for(int i=0;i<8;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if(a[tx][ty])
{
u[++lu]=a[tx][ty];
if(find(S)==find(a[tx][ty]))flag1s=1;
if(find(T)==find(a[tx][ty]))flag1t=1;
}
ty+=m;
if(!a[tx][ty])continue;
v[++lv]=a[tx][ty];
if(find(S)==find(a[tx][ty]))flag2s=1;
if(find(T)==find(a[tx][ty]))flag2t=1;
}
if((flag1s&&flag1t)||(flag2t&&flag2s))continue;
int flg=0;
if((flag1s&&flag2t)||(flag1t&&flag2s))
{
for(int i=1;i<=lu;i++)
for(int j=1;j<=lv;j++)
if(find(u[i])==find(v[j]))flg=1;
if(flg)continue;
}
a[x][y]=++cnt;fa[cnt]=cnt;a[x][y+m]=++cnt;fa[cnt]=cnt;ans++;
for(int i=1;i<=lu;i++)fa[find(u[i])]=find(cnt-1);
for(int i=1;i<=lv;i++)fa[find(v[i])]=find(cnt);
}
printf("%d\n",ans);
}
\(T3\)
第一眼,最小公倍数,莫比乌斯,\(n<=500?\)
\(dp\)即可
又忘记一件事情,就是\(lcm\)不能合并,想错好几次了,就是说不能把每个质因数拆出来单独算,拆出来之后我们算的是单独的,我们统计每一种之后加起来肯定是不对的
那么就考虑\(dp[i][j][k][x][y][z]\)表示每个小于\(17\)的质数的幂的方案数
大力转移即可
代码难看(转移压到了一行)。。
#include
#define mod 1000000007
#define ll long long
using namespace std;
int n,x;
ll ans;
int zhi[10]={0,2,3,5,7,11,13};//6
ll dp[8][5][4][3][3][3],f[8][5][4][3][3][3];
struct shu
{
int mx,s[10];
void Insert(int x)
{
for(int i=1;i<=6;++i) if(!(x%zhi[i])) while(!(x%zhi[i]))++s[i],x/=zhi[i];
mx=x;
}
friend bool operator <(const shu &a,const shu &b){return a.mx>b.mx;}
}e[N];
signed main()
{
freopen("f.in","r",stdin);
freopen("f.out","w",stdout);
cin>>n;
for(int i=1;i<=n;++i)scanf("%d",&x),e[i].Insert(x);
sort(e+1,e+1+n);dp[0][0][0][0][0][0]=1;
for(int i=1;i<=n;++i)
{
if(e[i-1].mx!=e[i].mx||e[i].mx==1)memcpy(f,dp,sizeof(dp));
for(int i2=7;i2>=0;--i2)for(int i3=4;i3>=0;--i3)for(int i5=3;i5>=0;--i5)for(int i7=2;i7>=0;--i7)for(int i11=2;i11>=0;--i11)for(int i13=2;i13>=0;--i13)(f[max(i2,e[i].s[1])][max(i3,e[i].s[2])][max(i5,e[i].s[3])][max(i7,e[i].s[4])][max(i11,e[i].s[5])][max(i13,e[i].s[6])]+=f[i2][i3][i5][i7][i11][i13])%=mod;
if(e[i+1].mx!=e[i].mx||e[i].mx==1||i==n)for(int i2=0;i2<=7;++i2)for(int i3=0;i3<=4;++i3)for(int i5=0;i5<=3;++i5)for(int i7=0;i7<=2;++i7)for(int i11=0;i11<=2;++i11)for(int i13=0;i13<=2;++i13)dp[i2][i3][i5][i7][i11][i13]+=(f[i2][i3][i5][i7][i11][i13]-dp[i2][i3][i5][i7][i11][i13])*e[i].mx%mod;
}
for(int i2=0,t2=1;i2<=7;++i2,t2*=2)for(int i3=0,t3=1;i3<=4;++i3,t3*=3)for(int i5=0,t5=1;i5<=3;++i5,t5*=5)for(int i7=0,t7=1;i7<=2;++i7,t7*=7)for(int i11=0,t11=1;i11<=2;++i11,t11*=11)for(int i13=0,t13=1;i13<=2;++i13,t13*=13)(ans+=(LL)t2*t3%mod*t5%mod*t7%mod*t11%mod*t13%mod*dp[i2][i3][i5][i7][i11][i13])%=mod;
cout<<((ans-1)%mod+mod)%mod;
fclose(stdin);
return 0;
}