2019 BUPT Winter Training #3 div.1

718C - A - Sasha and Array

f ⃗ ( n ) = ( f ( n + 1 ) , f ( n ) ) T \vec f(n)=(f(n+1),f(n))^T f (n)=(f(n+1),f(n))T,那么
f ⃗ ( n ) = A n f ⃗ ( 0 ) \vec f(n)=A^n\vec f (0) f (n)=Anf (0)
由于 f ⃗ ( 0 ) = ( 1 , 0 ) T \vec f(0)=(1,0)^T f (0)=(1,0)T,所以 f ( n ) = A n ( 2 ; 1 ) f(n)=A^n(2;1) f(n)=An(2;1).因为我们将其转化为了乘积关系,所以用线段树维护即可.

#include <cstdio>
#include <cstring>
typedef long long Matrixtype;
const int N=100000+5;
const int Dim=3;
const Matrixtype mod=1e9+7;
struct Matrix{
    Matrixtype a[Dim][Dim];
    inline Matrixtype* const operator[](const int _i){return a[_i];}
    void setsiz(int siz){a[0][0]=siz;}
    void empty(int siz=0){
        if(siz){a[0][0]=siz;for(int i=a[0][0];i;i--)for(int j=a[0][0];j;j--)a[i][j]=0;}
        else memset(a,0,sizeof(a));
    }
    void I(int siz){a[0][0]=siz;for(int i=siz;i;i--)for(int j=siz;j;j--)a[i][j]=(i==j);}
    void J(int siz){a[0][0]=siz;for(int i=siz;i;i--)for(int j=siz;j;j--)a[i][j]=1;}
    void copy(Matrix &b){
        a[0][0]=b[0][0];
        for(int i=a[0][0];i;i--){
            for(int j=a[0][0];j;j--)a[i][j]=b[i][j];
        }
    }
    void prt(){
        puts("--------------");
        for(int i=1;i<=a[0][0];i++,puts("")){
            for(int j=1;j<=a[0][0];j++)
                //printf("%d ",a[i][j]);
                printf("%I64d ",a[i][j]);
        }
    }
    Matrix operator*(Matrix &b)const{
        Matrix res;
        res[0][0]=a[0][0];
        for(int i=a[0][0];i;i--){
            for(int j=a[0][0];j;j--){
                res[i][j]=0;
                for(int k=a[0][0];k;k--){
                    res[i][j]+=a[i][k]*b[k][j];
                    res[i][j]%=mod;
                }
            }
        }
        // for(int i=a[0][0];i;i--){
        //     for(int j=a[0][0];j;j--){
        //         res[i][j]%=mod;
        //     }
        // }
        return res;
    }
    Matrix operator+(Matrix &b)const{
    	Matrix res;res[0][0]=a[0][0];
    	for(int i=1;i<=a[0][0];i++){
    		for(int j=1;j<=a[0][0];j++){
    			res[i][j]=(a[i][j]+b[i][j])%mod;
    		}
    	}
    	return res;
    }
    void pow(Matrixtype n,Matrix &res){
        Matrix x;
        res.I(a[0][0]);
        x.copy(*this);
        while(n){
            if(n&1)res=res*x;
            x=x*x; n>>=1;
        }
    }
}X,Y,mul[N<<2],sgt[N<<2];
long long a[N];
bool nid[N<<2];
void pushup(int p){
	sgt[p]=sgt[p<<1]+sgt[p<<1|1];
}
void pushdown(int p){
	if(nid[p]){
		sgt[p<<1]=sgt[p<<1]*mul[p];
		sgt[p<<1|1]=sgt[p<<1|1]*mul[p];
		mul[p<<1  ]=mul[p<<1  ]*mul[p];
		mul[p<<1|1]=mul[p<<1|1]*mul[p];
		nid[p<<1  ]=1;
		nid[p<<1|1]=1;

		mul[p].I(2);
		nid[p]=0;
	}
}
void build(int p,int l,int r){
	mul[p].I(2);
	if(l==r){
		X.pow(a[l],sgt[p]);
		return ;
	}
	int m=(l+r)>>1;
	build(p<<1,l,m);build(p<<1|1,m+1,r);
	pushup(p);
}
void update(int p,int l,int r,int L,int R,Matrix &X){
	if(L<=l&&r<=R){
		sgt[p]=sgt[p]*X;
		mul[p]=mul[p]*X;nid[p]=1;
		return ;
	}
	pushdown(p);  int m=(l+r)>>1;
	if(L<=m)update(p<<1  ,l  ,m,L,R,X);
	if(m< R)update(p<<1|1,m+1,r,L,R,X);
	pushup(p);
}
long long query(int p,int l,int r,int L,int R){
	if(L<=l&&r<=R){
		return sgt[p][2][1];
	}
	pushdown(p);  int m=(l+r)>>1;
	if(R<=m)return query(p<<1  ,l  ,m,L,R);
	if(m< L)return query(p<<1|1,m+1,r,L,R);
	return (query(p<<1,l,m,L,R)+query(p<<1|1,m+1,r,L,R))%mod;
}
long long res[N];int rtop=0;
void prt(long long c){res[++rtop]=c;}
int main(){
	X.empty(2);
	X[1][1]=1;X[1][2]=1;
	X[2][1]=1;X[2][2]=0;
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%I64d",&a[i]);
	build(1,1,n);
	while(m--){
		int o,l,r;
		scanf("%d%d%d",&o,&l,&r);
		if(o==1){
			long long x;
			scanf("%I64d",&x);
			X.pow(x,Y);
			update(1,1,n,l,r,Y);
		}
		else{
			prt(query(1,1,n,l,r));
		}
		//for(int i=1;i<=n;i++){printf("(%I64d)",query(1,1,n,i,i));}
	}
	for(int i=1;i<=rtop;i++)printf("%I64d\n",res[i]);
}

618E - C - Wet Shark and Blocks

d p ⃗ x × 1 ( i ) \vec{dp}_{x\times 1}(i) dp x×1(i) i i i长度数字的方案数,根据:
d p ( i ) [ ( j ⋅ 10 + k ) % x ] = d p ( i − 1 ) [ j ] ⋅ f a c [ k ] dp(i)[(j\cdot 10+k)\%x]=dp(i-1)[j]\cdot \mathrm{fac}[k] dp(i)[(j10+k)%x]=dp(i1)[j]fac[k]
得到 d p ⃗ ( i ) = A d p ⃗ ( i − 1 ) \vec{dp}(i)=A\vec{dp}(i-1) dp (i)=Adp (i1).转移即可.
还可以根据 1 0 k 10^k 10k最多 x x x个不同的取值转移,但是太过麻烦我写烂了…

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long Matrixtype;
const int Dim=101;
const Matrixtype mod=1e9+7;
struct Matrix{
    Matrixtype a[Dim][Dim];
    inline Matrixtype* const operator[](const int _i){return a[_i];}
    void setsiz(int siz){a[0][0]=siz;}
    void empty(int siz=0){
        if(siz){a[0][0]=siz;for(int i=a[0][0];i;i--)for(int j=a[0][0];j;j--)a[i][j]=0;}
        else memset(a,0,sizeof(a));
    }
    void I(int siz){a[0][0]=siz;for(int i=siz;i;i--)for(int j=siz;j;j--)a[i][j]=(i==j);}
    void J(int siz){a[0][0]=siz;for(int i=siz;i;i--)for(int j=siz;j;j--)a[i][j]=1;}
    void copy(Matrix &b){
        a[0][0]=b[0][0];
        for(int i=a[0][0];i;i--){
            for(int j=a[0][0];j;j--)a[i][j]=b[i][j];
        }
    }
    void prt(){
        puts("--------------");
        for(int i=1;i<=a[0][0];i++,puts("")){
            for(int j=1;j<=a[0][0];j++)
                //printf("%d ",a[i][j]);
                printf("%I64d ",a[i][j]);
        }
    }
    Matrix operator*(Matrix &b)const{
        Matrix res;
        res[0][0]=a[0][0];
        for(int i=a[0][0];i;i--){
            for(int j=a[0][0];j;j--){
                res[i][j]=0;
                for(int k=a[0][0];k;k--){
                    res[i][j]+=a[i][k]*b[k][j];
                    res[i][j]%=mod;
                }
            }
        }
        // for(int i=a[0][0];i;i--){
        //     for(int j=a[0][0];j;j--){
        //         res[i][j]%=mod;
        //     }
        // }
        return res;
    }
    void pow(Matrixtype n,Matrix &res){
        Matrix x;
        res.I(a[0][0]);
        x.copy(*this);
        while(n){
            if(n&1)res=res*x;
            x=x*x; n>>=1;
        }
    }
};
Matrix X[(sizeof(Matrixtype)<<2)+1],tr,ans;
void premat(Matrixtype n,Matrix &Mat){
    int k=1;X[0].copy(Mat);
    while(n>>k){
        X[k]=X[k-1]*X[k-1];k++;
    }
}
void prepow(Matrixtype n,Matrix &res){
    res.I(X[0][0][0]);
    for(int bit=0;n>>bit;bit++){
        if((n>>bit)&1)res=res*X[bit];
    }
}
long long qp(long long a,long long b){
	long long res=1;
	while(b){
		if(b&1)res=res*a%mod;
		a=a*a%mod;b>>=1;
	}
	return res;
}
long long ten[200];
long long fac[200];
int main(){
	int n,k,x;long long b;
	scanf("%d%I64d%d%d",&n,&b,&k,&x);
	for(int i=1;i<=n;i++){
		int t;
		scanf("%d",&t);
		fac[t]++;
	}
	for(int i=x;i<=10;i++)fac[i%x]+=fac[i];
	tr.empty(x);
	for(int i=0;i<x;i++){
		for(int j=0;j<x;j++)tr[(i*10+j)%x+1][i+1]+=fac[j];
	}
	premat(b,tr);prepow(b,ans);
	printf("%I64d\n",ans[k+1][1]);
}

325E - F - The Red Button

很容易发现奇数情况是不行的,再证明偶数情况:
我们设 G G G是标号图.
对于任意 i i i,有 i / 2 i/2 i/2 ( i + N ) / 2 (i+N)/2 (i+N)/2指向它.同时它的出度为 2 2 2.
所以 G G G 2 2 2-正则图.下面有三个定理:
定理1 任意 d d d-正则图是线图.
定理2 L ( G ) L(G) L(G) 2 d − 2 2d-2 2d2-正则图当且仅当 G G G d d d-正则图.
定理3 G G G是欧拉图当且仅当 L ( G ) L(G) L(G)是哈密顿图.
我大致已经证了求线图的原图也即 L − 1 ( G ) L^{-1}(G) L1(G) N P \mathrm{NP} NP- h a r d hard hard问题.但并不妨碍做题.
根据定理 1 1 1我们知道 G G G是线图,也就是存在 L − 1 ( G ) L^{-1}(G) L1(G).根据定理 2 2 2知道 L − 1 ( G ) L^{-1}(G) L1(G) 2 2 2-正则图,所以 L − 1 ( G ) L^{-1}(G) L1(G)有欧拉回路,对应 G G G的一个哈密顿回路。因为是 2 − 2- 2正则图.所以随意走动我们都能得到一个欧拉路(根据某个忘记名字的算法,我们在 2 2 2-正则图上一直走割边所以有一个欧拉路)…

#include <cstdio>
#include <cstring>
const int N=1e5+5;
bool vis[N];int n,res[N],rtop=0;
void dfs(int u){
	if(vis[u])return ;
	vis[u]=1;
	dfs((u<<1)%n);dfs((u<<1|1)%n);
	res[++rtop]=u;
}
int main(){
	scanf("%d",&n);
	if(n&1){
		puts("-1");
		return 0;
	}
	dfs(0);
	while(rtop)printf("%d ",res[rtop--]);
	printf("0\n");
}

717E - G - Paint it really, really dark gray

dfs搜索即可,别犯智障错误就行orz

#include <cstdio>
#include <cstring>
const int N=2e5+5,M=N*2;
const int Headsize=N,Edgesize=M;
int head[Headsize+5],mal;
struct edge{
	int nx,to;
}e[Edgesize+5];
inline void init(){
    mal=1;
    memset(head,0,sizeof(head));
}
inline void addedge(int u,int v){
	e[mal].to=v;e[mal].nx=head[u];head[u]=mal++;
}
int col[N],has[N];
void dfs(int u,int f){
	has[u]=col[u];
	for(int i=head[u];i;i=e[i].nx){
		int v=e[i].to;
		if(v==f)continue;
		dfs(v,u);
		has[u]|=has[v];
	}
}
void ptr(int u,int f){
	printf("%d ",u);col[u]^=1;
	for(int i=head[u];i;i=e[i].nx){
		int v=e[i].to;
		if(v==f)continue;
		if(has[v]){
			ptr(v,u);
			printf("%d ",u);col[u]^=1;
		}
	}
	if(col[u]){
		if(f){
			printf("%d %d ",f,u);col[f]^=1;col[u]^=1;
		}else{
			//puts("here");
			printf("%d %d %d",e[head[u]].to,u,e[head[u]].to);
		}
	}
}
int main(){
	int n;
	scanf("%d",&n);
	init();
	for(int i=1;i<=n;i++){
		int t;
		scanf("%d",&t);
		if(t==1)col[i]=0;else col[i]=1;
	}
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
	}
	dfs(1,0);
	if(!has[1]){
		//puts("here");
		puts("1");
	}else{
		printf("%d %d %d %d ",1,e[head[1]].to,1,e[head[1]].to);
		col[1]^=1;
		ptr(1,0);
	}
}

623B - H - Array GCD

根据我写的错解可以发现 p r e pre pre之间有覆盖关系, s u f suf suf也是.
先求 p r e pre pre的素因子 s s s可以覆盖所有方案,再用同样的方法转移 s u f suf suf.
我们显然有:
r e s = min ⁡ i , j , s { p r e [ i ] [ s ] + s u f [ j ] [ s ] + ( j − 1 − i ) a } res=\min_{i,j,s}\{pre[i][s]+suf[j][s]+(j-1-i)a\} res=i,j,smin{pre[i][s]+suf[j][s]+(j1i)a}
r e s i = min ⁡ s { p r e i + min ⁡ j { ( s u f j + j a ) } } − ( i + 1 ) a . res_i=\min_{s}\{pre_i+\min_{j}\{(suf_j+ja)\}\}-(i+1)a. resi=smin{prei+jmin{(sufj+ja)}}(i+1)a.
暴力转移即可…

#include <cstdio>
#include <map>
#include <cmath>
#include <cstring>
#include <utility>
using namespace std;
const int N=1e6+5;
long long pre[N][32],suf[2][32],gor[32];int q=0,prim[32],qq=0,pp[32];
int gcd(int a,int b){
	int r;
	while(b){r=a%b;a=b;b=r;}
	return a;
}
int n;
void Ins(int x,long long b,long long *val,int &q,int *prim){
	int sqrtx=(int)sqrt(x+1);
	for(int i=2;i<=sqrtx;i++){
		if(x%i==0){
			x/=i;
			while(x%i==0)x/=i;
			bool f=1;
			for(int j=1;j<=q;j++)if(prim[j]==i){val[j]=min(val[j],b),f=0;break;}
			if(f){prim[++q]=i;
						val[q]=b;
					}}
	}
	if(x>1){
		bool f=1;
		for(int j=1;j<=q;j++)if(prim[j]==x){val[j]=min(val[j],b),f=0;break;}
		if(f){prim[++q]=x;
				val[q]=b;}
	}
}
long long x[N],res=0x7fffffffffffffffLL;
pair<int,int> incheck[1000];
int main(){
	long long a,b;
	memset(pre,0x3f,sizeof(pre));
	memset(suf,0x3f,sizeof(suf));
	scanf("%d%I64d%I64d",&n,&a,&b);
	for(int i=1;i<=n;i++)scanf("%I64d",&x[i]);
	res=(n-1)*a;
	// if(x[1]-1>1)pre[1][x[1]-1]=b;
	// pre[1][x[1]]=0;pre[1][x[1]+1]=b;
	// int y;
	// for(int i=2;i<=n;i++){
	// 	for(auto c:pre[i-1]){
	// 		y=gcd(c.first,x[i]-1);
	// 		if(y>1){
	// 			if(pre[i].count(y))pre[i][y]=min(pre[i][y],c.second+b);else pre[i][y]=c.second+b;
	// 			res=min(pre[i][y]+(n-i)*a,res);
	// 		}
	// 		y=gcd(c.first,x[i]);
	// 		if(y>1){
	// 			if(pre[i].count(y))pre[i][y]=min(pre[i][y],c.second);else pre[i][y]=c.second;
	// 			res=min(pre[i][y]+(n-i)*a,res);
	// 		}
	// 		y=gcd(c.first,x[i]+1);
	// 		if(y>1){
	// 			if(pre[i].count(y))pre[i][y]=min(pre[i][y],c.second+b);else pre[i][y]=c.second+b;
	// 			res=min(pre[i][y]+(n-i)*a,res);
	// 		}
	// 	}
	// }
	// for(int i=1;i<=n;i++){
	// 	printf("%d:\n",i);
	// 	for(auto c:pre[i]){
	// 		printf("(%d,%I64d)",c.first,c.second);
	// 	}
	// 	puts("");
	// }
	// if(x[n]-1>1)suf[n][x[n]-1]=b;
	// suf[n][x[n]]=0;suf[n][x[n]+1]=b;
	// for(int i=n-1;i;i--){
	// 	for(auto c:suf[i+1]){
	// 		y=gcd(c.first,x[i]-1);
	// 		if(y>1){
	// 			if(suf[i].count(y))
	// 				suf[i][y]=min(suf[i][y],c.second+b);else suf[i][y]=c.second+b;
	// 			res=min(suf[i][y]+(i-1)*a,res);
	// 		}
	// 		y=gcd(c.first,x[i]);
	// 		if(y>1){
	// 			if(suf[i].count(y))
	// 				suf[i][y]=min(suf[i][y],c.second);else suf[i][y]=c.second;
	// 			res=min(suf[i][y]+(i-1)*a,res);
	// 		}
	// 		y=gcd(c.first,x[i]+1);
	// 		if(y>1){
	// 			if(suf[i].count(y))
	// 				suf[i][y]=min(suf[i][y],c.second+b);else suf[i][y]=c.second+b;
	// 			res=min(suf[i][y]+(i-1)*a,res);
	// 		}
	// 	}
	// }
	// puts("");
	// for(int i=n;i>=1;i--){
	// 	printf("%d:\n",i);
	// 	for(auto c:suf[i]){
	// 		printf("(%d,%I64d)",c.first,c.second);
	// 	}
	// 	puts("");
	// }
	// for(auto c:pre[n]){
	// 	res=min(res,c.second);
	// 	gor[c.first]=c.second+n*a;
	// }
	Ins(x[1]-1,b,pre[1],q,prim);
	Ins(x[1],0,pre[1],q,prim);
	Ins(x[1]+1,b,pre[1],q,prim);
	// for(int i=1;i<=q;i++){
	// 	printf("[%I64d,%d]",pre[1][i],prim[i]);
	// }
	// puts("");
	// printf("%I64d\n",res);
	for(int i=2;i<=n;i++){
		for(int j=1;j<=q;j++){
			if(x[i]%prim[j]==0){
				pre[i][j]=min(pre[i][j],pre[i-1][j]);res=min(res,pre[i][j]+(n-i)*a);
			}
			if((x[i]+1)%prim[j]==0){
				pre[i][j]=min(pre[i][j],pre[i-1][j]+b);res=min(res,pre[i][j]+(n-i)*a);
			}
			if((x[i]-1)%prim[j]==0){
				pre[i][j]=min(pre[i][j],pre[i-1][j]+b);res=min(res,pre[i][j]+(n-i)*a);
			}
		}
	// 	printf("----------\n%d:\n",i);
	// 	for(int j=1;j<=q;j++){
	// 		printf("[%I64d,%d]",pre[i][j],prim[j]);
	// 	}
	// 	puts("");
	// printf("rres%I64d\n",res);
	}
	Ins(x[n]-1,0,suf[0],qq,pp);
	Ins(x[n],0,suf[0],qq,pp);
	Ins(x[n]+1,0,suf[0],qq,pp);
	// for(int i=1;i<=qq;i++){
	// 	printf("[%I64d,%d]",suf[0][i],pp[i]);
	// }
	// puts("");
	int g=0;
	for(int i=1;i<=q;i++){
		for(int j=1;j<=qq;j++){
			if(prim[i]==pp[j])incheck[++g]={i,j};
		}
	}
	int qwq=0;
	memset(gor,0x3f,sizeof(gor));
	//printf("%I64d\n",res);
	for(int i=n-1,j=n;j!=0;i--,j--){
		qwq^=1;
		memset(suf[qwq],0x3f,sizeof(suf[qwq]));
		for(int s=1;s<=qq;s++){
			if((x[j]-1)%pp[s]==0){
				suf[qwq][s]=min(suf[qwq][s],suf[qwq^1][s]+b);
				res=min(res,suf[qwq][s]+i*a);
			}
			if((x[j])%pp[s]==0){
				suf[qwq][s]=min(suf[qwq][s],suf[qwq^1][s]);
				res=min(res,suf[qwq][s]+i*a);
			}
			if((x[j]+1)%pp[s]==0){
				suf[qwq][s]=min(suf[qwq][s],suf[qwq^1][s]+b);
				res=min(res,suf[qwq][s]+i*a);
			}
		}
		// printf("---------\n%d:\n",j);
		// for(int k=1;k<=qq;k++){
		// 	printf("[%d,%I64d]",pp[k],suf[qwq][k]);
		// }
		// puts("");
		// printf("%I64d\n",res);
		if(i)for(int s=1;s<=qq;s++)gor[s]=min(suf[qwq][s]+j*a,gor[s]);
		// for(int s=1;s<=qq;s++){
		// 	if(gor.count(prim[s])){
		// 		gor[prim[s]]=min(suf[qwq][s]+j*a,gor[prim[s]]);
		// 	}else {
		// 		for(int k=-1;k<=1;k++){
		// 			if(gcd(t.first,prim[s])>1){gor[prim[s]]=suf[qwq][s]+j*a;break;}
		// 		}
		// 	}
		// }
		// for(int k=1;k<=q;k++){
		// 	for(int s=1;s<=qq;s++){
		//		if(prim[k]==pp[s]){
		if(i)for(int k=1;k<=g;k++)res=min(res,pre[i][incheck[k].first]+gor[incheck[k].second]-j*a);
		//		}
		// 	}
		// }
	}
	printf("%I64d\n",res);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值