C
构造一个矩阵,然后采用矩阵快速幂
#include <iostream> #include <algorithm> #include <string.h> #include <cstdio> #include <vector> using namespace std; typedef long long LL; const LL mod = 1000000007; const int maxn=1<<7; struct Matix { LL m[maxn][maxn]; int n; Matix mul(Matix &rhs) { Matix ans; for(int i=0; i<n; i++) for(int j=0; j<n; j++) { ans.m[i][j]=0; for(int k=0; k<n; k++) ans.m[i][j]=(ans.m[i][j]+m[i][k]*rhs.m[k][j])%mod; } ans.n=n; return ans; } }; Matix T; LL powmod(int n,int m) { Matix ans,A=T; ans.n=1<<m; memset(ans.m,0,sizeof(ans.m)); for(int i=0; i<ans.n; i++) ans.m[i][i]=1; while(n){ if(n&1)ans=ans.mul(A); n>>=1; A=A.mul(A); } LL an=0; for(int i=0; i<ans.n; i++){ an=(ans.m[i][0]+an)%mod; } return an; } int jud(int A, int B, int m) { for(int i=0; i<m; i++) { if(A&(1<<i)){ if(B&(1<<i))continue; if(i&&(B&(1<<(i-1)))>0 && (A&(1<<(i-1)))==0 )return 0; if(i!=m-1&&(B&(1<<(i+1)))>0&&(A&(1<<(i+1)))==0)return 0; } } return 1; } int main() { int n,m; while(scanf("%d%d",&n,&m)==2) { for(int i=0; i<(1<<m); i++) { for(int j=0; j<(1<<m); j++) { T.m[i][j]=jud(i,j,m); } } T.n=(1<<m); printf("%I64d ",powmod(n,m)); } return 0; }
D
计算[a,b]之间的所有数的各个位置异或然后整个区间求和, 我们用d[i][j]表示在第i位时异或为j的个数,然后我们枚举每一位,求和就好了,因为10以内的数异或小于16
#include <iostream> #include <algorithm> #include <string.h> #include <cstdio> using namespace std; typedef long long LL; const LL mod = 1000000007; const int maxn=100000+10; LL dp[maxn][10],d[maxn][16]; void solve() { d[0][0]=1; for(int i=1; i<100001; i++) { for(int j=0; j<10; j++) for(int r=0; r<16; r++){ d[i][r]=d[i][r]+d[i-1][r^j]; if(d[i][r]>=mod)d[i][r]-=mod; } } } char str[maxn]; LL look(int n,int op) { int nt=0; LL ans=0; for(int i=n; i>0; i--){ int lit=str[n-i]-'0'; for(int j=0; j<lit; j++){ int dr=nt^j; for(int k=0; k<16; k++){ ans=(ans+d[i-1][k^dr]*k )%mod; } } nt^=lit; } if(op) ans=(ans+nt)%mod; return ans; } int main() { int cas; solve(); scanf("%d",&cas); for(int cc=1 ;cc<=cas; cc++) { LL ans=0; scanf("%s",str); int len=strlen(str); ans=ans-look(len,0); scanf("%s",str); len=strlen(str); LL a1=look(len,1); ans=( (ans+a1)%mod+mod )%mod; printf("Case #%d: %I64d ",cc,ans); } return 0; }
E
给了一棵树50000个节点求从100000 次查询 每次给了两个点求两个节的路径最小并且最大值最大,每个叶子节点能回到1这个节点,我们考虑几种情况,
树上直接链的 , 还有就是通过叶子节点回到1 1再转化, 这里有个坑点就是 一个点可以到叶子节点后 还可能通过他的父亲到达叶子节点,不一定是通过他的孩子,坑了好久
#include <iostream> #include <algorithm> #include <cstdio> #include <string.h> #include <vector> using namespace std; typedef long long LL; const int numofedg=100000+10; const int maxn=500005; int H[maxn],nx[numofedg],to[numofedg],numofE,val[maxn]; int son[maxn],num[maxn],fa[maxn],top[maxn],p[maxn],fp[maxn],pos,depth[maxn],ans[maxn]; int minDown[maxn],maxDown[maxn],minUp[maxn],maxUp[maxn]; void init(int n) { val[0]=0;maxUp[0]=minUp[0]=0; numofE=0;pos=0; memset(H,0,sizeof(H)); } void addedg(int a, int b){ numofE++; to[numofE]=b; nx[numofE]=H[a]; H[a]=numofE; } void panduan(int &L, int &V, int L2,int V2){ if(L>=L2){ if(L == L2 ){ V=V>V2?V:V2; }else { L=L2; V=V2; } } } void dfs(int cur, int per, int dep) { depth[cur]=dep; son[cur]=-1; fa[cur]=per; num[cur]=1; maxUp[cur]=max( val[ cur ] , maxUp[ per ] ); minUp[cur]=minUp[per] + val[cur]; maxDown[ cur ]=-1; minDown[ cur ]=1000000000; for(int i=H[cur]; i>0 ; i=nx[i]) { int tto=to[i]; if(tto==per)continue; dfs(tto,cur,dep+1); num[cur]+=num[tto]; panduan(minDown[cur],maxDown[cur],minDown[tto],maxDown[tto]); if( son[cur]==-1 || num[ son[cur] ] < num[ tto ] )son[cur]=tto; } if(son[cur]!=-1){ maxDown[cur]=max(maxDown[cur],val[cur]); minDown[cur]+=val[cur]; }else{ maxDown[cur]=val[cur]; minDown[cur]=val[cur]; } } void finde(int cur ,int per, int xx) { top[cur]=xx; pos++; p[cur]=pos; fp[pos]=cur; if(son[cur]!=-1) finde(son[cur],cur,xx); for(int i=H[cur]; i>0; i=nx[i]) { if(to[i]==son[cur]||to[i]==per)continue; finde(to[i],cur,to[i]); } } struct Itree { int sum[maxn*5],maxval[ maxn*5],CL,CR; int S,Ma; void build(int L, int R, int o) { if(L==R) { maxval[ o ] = sum[ o ] = val[ fp[L] ]; return ; } int mid=(L+R)>>1; build(L,mid,o*2); build(mid+1,R,o*2+1); maxval[o]=max(maxval[o*2],maxval[o*2+1]); sum[o]=sum[o*2]+sum[o*2+1]; } void query(int L, int R, int o) { if(CL<=L&&R<=CR){ S=S+sum[o]; Ma=max(maxval[o],Ma); return ; } int mid=(L+R)>>1; if(CL<=mid) query(L,mid,o*2); if(CR>mid) query(mid+1,R,o*2+1); } }T; struct QE{ int L,R; QE(int cL=0,int cR=0){ L=cL; R=cR; } }; vector<QE>Qnu; void solve(int x, int y) { int f1=top[x],f2=top[y]; while(f1!=f2){ if(depth[f1]<depth[f2]){ int temp=x;x=y; y=temp; temp=f1;f1=f2;f2=temp; } Qnu.push_back( QE(p[f1],p[x]) ); x=fa[f1]; f1=top[x]; } if(depth[x]>depth[y]){ int temp=x; x=y; y=temp; } Qnu.push_back(QE(p[x],p[y])); } void jud2(int u, int v, int &L, int &V,int n) { Qnu.clear(); solve(u,v); T.S=0; T.Ma=-1; for(int i=0; i<Qnu.size(); i++) { QE t=Qnu[i]; T.CL=min(t.L,t.R); T.CR=max(t.L,t.R); T.query(1,n,1); } L=T.S;V=T.Ma; } void dfs2(int cur, int per) { if(cur!=1){ panduan(minDown[cur],maxDown[cur],minDown[per]+val[cur],max(maxDown[per],val[cur])); } for(int i=H[cur]; i>0; i=nx[i]) dfs2(to[i],cur); } void jud1(int uu, int vv, int &L, int &V) { L=minDown[uu]+minUp[vv]; V=max(maxDown[uu],maxUp[vv]); int L2,V2; L2=minDown[uu]+minDown[vv]+val[1]; V2=max(maxDown[uu],max(maxDown[vv],val[1])); panduan(L,V,L2,V2); L2=minUp[uu]+minDown[vv]; V2=max(maxUp[uu],maxDown[vv]); panduan(L,V,L2,V2); } int main() { int cas,n,m; scanf("%d",&cas); for(int cc=1; cc<=cas ;cc++) { scanf("%d%d",&n,&m); init(n); for(int i=2; i<=n; i++) { int d; scanf("%d",&d); addedg(d,i); } for(int i=1; i<=n; i++) { scanf("%d",&val[i]); } dfs(1,0,0); finde(1,0,1); T.build(1,n,1); dfs2(1,0); for(int i=0; i<m; i++) { int u,v; scanf("%d%d",&u,&v); if(u==v){ printf("%d %d ",val[u],val[v]); continue; } int L,V; jud1(u,v,L,V); int L2,V2; jud2(u,v,L2,V2,n); panduan(L,V,L2,V2); printf("%d %d ",L,V); } } return 0; }