zoukankan      html  css  js  c++  java
  • 自测题 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;
    }
    

      

  • 相关阅读:
    Linux常用命令大全详解
    C++语言关键字及注解
    求两数的最大公约数
    ICOP完成端口详解
    C/C++常见面试题
    猴子吃桃问题之《C语言经典案例分析》
    DTD
    DTD
    DTD的使用
    Rust
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9081793.html
Copyright © 2011-2022 走看看