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;
    }
    

      

  • 相关阅读:
    积水路面Wet Road Materials 2.3
    门控时钟问题
    饮料机问题
    Codeforces Round #340 (Div. 2) E. XOR and Favorite Number (莫队)
    Educational Codeforces Round 82 (Rated for Div. 2)部分题解
    Educational Codeforces Round 86 (Rated for Div. 2)部分题解
    Grakn Forces 2020部分题解
    2020 年百度之星·程序设计大赛
    POJ Nearest Common Ancestors (RMQ+树上dfs序求LCA)
    算法竞赛进阶指南 聚会 (LCA)
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9081793.html
Copyright © 2011-2022 走看看