自测题 5.23晚 ~ 5.24早

T1:

     很随便的就能想出来,设 f(i) 为各个位数和为i的数的个数,g(i) 为 。。。。和为i的数的和,然后可以发现递推的系数都是常数,矩阵转移即可。

     但是 m^n 可能要高精度表示?? 别忘了可以在算出 d(m^i) 的答案矩阵的基础上 直接m次幂直接算出 d(m^(i+1)) 的答案矩阵。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
#define M(x) memset(x,0,sizeof(x))
const int ha=1e9,maxn=23;

inline void ADD(int &x,int y){ x+=y; if(x>=ha) x-=ha;}

void W(int x,int L){ if(L) W(x/10,L-1); putchar(x%10+'0');}

int n,m,ans;

struct node{
	int a[maxn][maxn];
	
	inline void clear(){ M(a);}
	inline void Base(){ clear(); for(int i=1;i<=18;i++) a[i][i]=1;}
	
	node operator *(const node &u)const{
		node r; r.clear();
		for(int k=1;k<=18;k++)
		    for(int i=1;i<=18;i++)
		        for(int j=1;j<=18;j++) ADD(r.a[i][j],a[i][k]*(ll)u.a[k][j]%ha);
		return r;
	}
}b,ANS;

inline void build(){
	b.clear();
	for(int i=1;i<9;i++) ADD(b.a[i][i+1],1);
	for(int i=10;i<18;i++) ADD(b.a[i][i+1],1);
	for(int i=1;i<=9;i++) ADD(b.a[i][1],1),ADD(b.a[i][10],i);
	for(int i=10;i<=18;i++) ADD(b.a[i][10],10);
}

inline void calc(){
	ANS.Base();
	node x=b; int y=m;
	
	for(;y;y>>=1,x=x*x) if(y&1) ANS=ANS*x;
	
	ADD(ans,ANS.a[1][10]);
	
	b=ANS;
}

inline void solve(){
	build();
	for(int i=1;i<=n;i++) calc();
}

int main(){
//	freopen("num.in","r",stdin);
//	freopen("num.out","w",stdout);
	
	scanf("%d%d",&n,&m);
	solve();
	if(n<=3&&m<=2) printf("%d
",ans);
	else W(ans,8),puts("");
	return 0;
}

  

T2:

     真是深黑数论题啊23333

     可以发现底数是 n%p ,指数是 2n % (p-1)。

    所以我们可以先设 now = n % p,然后求出满足 now^y + now^m = x (mod p) 的y,并且要保证y是偶数(因为p-1肯定是偶数,2在这个同余系下是没有逆元的) (一个离散对数就行了)

    所以我们现在就得到了 : n % p = now ; n % (p-1) = y/2。

    这个玩意手玩中国剩余定理就行了,都不用上模板23333(但注意模数是long long的时候要用快速乘)

   好像忘了说now咋找了。。。怕出题人卡我我是随机的now,效果还不错2333

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<map>
#define ll long long
using namespace std;

map<int,int> mmp;

int b,m,p,now,sz;
ll ans;

inline int add(int x,int y,const int ha){ x+=y; return x>=ha?x-ha:x;}
inline int ksm(int x,int y,const int ha){
	int an=1;
	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
	return an;
}

inline ll ADD(ll x,ll y,const ll ha){ x+=y; return x>=ha?x-ha:x;}
inline ll ksc(ll x,ll y,const ll ha){
	ll an=0;
	for(;y;y>>=1,x=ADD(x,x,ha)) if(y&1) an=ADD(an,x,ha);
	return an;
}
inline ll fpow(ll x,ll y,const ll ha){
	ll an=1;
	for(;y;y>>=1,x=ksc(x,x,ha)) if(y&1) an=ksc(an,x,ha);
	return an;
}

inline bool can(){
	mmp.clear();
	bool flag=0;
	
	int u=add(b,p-ksm(now,m,p),p),v=1,inv=ksm(ksm(now,sz,p),p-2,p);
	for(int i=0;i<sz;i++,v=v*(ll)now%p) if(!mmp.count(v)) mmp[v]=i;
	
	v=u; int z;
	for(int i=0;i<sz;i++,v=v*(ll)inv%p) if(mmp.count(v)&&!((i*sz+mmp[v])&1)){
		z=i*sz+mmp[v],flag=1;
		break;
	}
	
	if(!flag) return 0;
	
	z>>=1;
	ll to=p*(ll)(p-1);
	ans=ADD(ksc(z,ksc(p,p,to),to),ksc(now,ksc(p-1,p-1,to),to),to);
	return 1;
}

inline void solve(){
	while(1){
		now=rand()%p;
		if(now) if(can()) break;
	}
}

int main(){
	
//	freopen("theory.in","r",stdin);
//	freopen("check.out","w",stdout);
	
	srand(time(0));
	
	scanf("%d%d%d",&b,&m,&p),sz=sqrt(p)+3;
	
	solve();
	printf("%lld
",ans);
	
	
//	if(add(ksm(ans%p,ans%(p-1)+ans%(p-1),p),ksm(ans%p,m,p),p)==b%p) puts("yes");
//	else puts("no");
	
	return 0;
}

  

T3:

    题目已经传到我校OJ上了: http://lifecraft-mc.com:81/problem/1232

    显然这是一个套路题,我们可以很轻松的通过dfs序把子树询问放到线段树的一个区间里,那么现在的问题是access的时候该怎么维护呢?

    当我们要把一个点和它爸爸之间的边从轻边变成重边的时候,显然这个点的子树到根的轻边数都会-1,线段树区间加法就行了(可能标记永久化会快一点,反正我写的这个)。

    但如果父亲原来就有重儿子的话,那条边是会变成轻边的,所以那颗子树对应的区间会区间+1。

  

    当然不能直接修改splay的根对应的节点,因为重链的顶端对应的节点是splay中序遍历最小的节点,所以还需要写一个找重链顶端的函数。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<ctime>
#define ll long long
using namespace std;
#define D double
#define mid (l+r>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
const int maxn=150005;
int hd[maxn],ne[maxn*2],to[maxn*2],num;
int f[maxn],ch[maxn][2],n,m,dc,dfn[maxn];
int le,ri,tag[maxn*4],siz[maxn],w,Q,pos;
ll sum[maxn*4],ans;
char C;

inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}

inline int read(){
	int x=0; char ch=getchar();
	for(;!isdigit(ch);ch=getchar());
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return x+1;
}

void dfs(int x,int fa){
	f[x]=fa,dfn[x]=++dc,siz[x]=1;
	
	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){
		dfs(to[i],x);
		siz[x]+=siz[to[i]];
	}
}

inline bool isroot(int x){ return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;}
inline int Get(int x){ return ch[f[x]][1]==x;}

inline void maintain(int x){ }

inline void rotate(int x){
	int fa=f[x],ffa=f[fa],tp=Get(x);
	
	ch[fa][tp]=ch[x][tp^1],f[ch[fa][tp]]=fa;
	
	ch[x][tp^1]=fa,f[fa]=x;
	
	f[x]=ffa;
	if(ch[ffa][0]==fa||ch[ffa][1]==fa) ch[ffa][ch[ffa][1]==fa]=x;
	
	maintain(fa),maintain(x);
}

inline void splay(int x){
	for(;!isroot(x);rotate(x))
	    if(!isroot(f[x])) rotate(Get(f[x])==Get(x)?f[x]:x);
}

inline int getroot(int x){
	while(ch[x][0]) x=ch[x][0];
	return x;
}

void update(int o,int l,int r){
	if(l>=le&&r<=ri){ sum[o]+=w*(ll)(r-l+1),tag[o]+=w; return;}
	
	if(le<=mid) update(lc,l,mid);
	if(ri>mid) update(rc,mid+1,r);
	
	sum[o]=sum[lc]+sum[rc]+tag[o]*(ll)(r-l+1);
}

void query(int o,int l,int r,int Tag){
	if(l>=le&&r<=ri){ ans+=sum[o]+Tag*(ll)(r-l+1); return;}
	
	if(le<=mid) query(lc,l,mid,Tag+tag[o]);
	if(ri>mid) query(rc,mid+1,r,Tag+tag[o]);
}

inline void access(int x){
	for(int pre=0,now;x;pre=x,x=f[x]){
		splay(x);
		
		now=ch[x][1],ch[x][1]=0;
		
		if(now){
			splay(now),now=getroot(now);
			le=dfn[now],ri=le+siz[now]-1;
			w=1,update(1,1,n);
		}
		
		if(pre){
		    now=getroot(pre);
		    le=dfn[now],ri=le+siz[now]-1;
		    w=-1,update(1,1,n);
		}
		
		ch[x][1]=pre;
	    
	//	maintain(x);
	}
}

inline void solve(){
	for(int i=2;i<=n;i++) le=dfn[i],ri=le+siz[i]-1,w=1,update(1,1,n);
	
	scanf("%d",&Q);
	while(Q--){
		C=getchar();
		while(C!='O'&&C!='q') C=getchar();
		pos=read();
		
		if(C=='q'){
			ans=0,le=dfn[pos],ri=le+siz[pos]-1;
			query(1,1,n,0),printf("%.0lf
",ans/(D)siz[pos]+1e-9);
		}
		else access(pos);
	}
} 

int main(){
//	freopen("tong.in","r",stdin);
//	freopen("ans.out","w",stdout);
	
	scanf("%d",&n);
	int uu,vv;
	for(int i=1;i<n;i++) uu=read(),vv=read(),add(uu,vv),add(vv,uu);
	dfs(1,0);
	solve();
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/9081793.html