2017.11.03离线赛总结
2017-11-04 16:01
169 查看
excellent ——3802
思路:首先显然可以看出是枚举i个a,得到n-i个b,但组合数只有70,而且还有mod,那么当然要通过逆元+费马小定理来快速幂掉。#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<queue> using namespace std; #define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++) #define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--) #define LL long long #define db double #define INF 0x3f3f3f3f #define inf 0x7fffffff #define mcl(a,b) memset(a,b,sizeof(a)) #define Sz(a) sizeof(a) #define pb push_back #define N 1000005 #define P 1000000007 int a,b,n; bool check(int x){ while(x>0){ int y=x%10; if(y!=a && y!=b)return 0; x/=10; } return 1; } struct p40{ int ans; void dfs(int x,int sum){ if(x==n){ if(check(sum)){ ans++; if(ans>=P)ans-=P; } return; } dfs(x+1,sum+a); dfs(x+1,sum+b); } void solve(){ dfs(0,0); cout<<ans<<endl; } }p40; struct p70{ int ans; int C[1505][1505]; void Init(){ C[0][0]=1; REP(i,1,1500){ C[i][0]=1; REP(j,1,i)(C[i][j]=C[i-1][j-1]+C[i-1][j])%=P; } } void solve(){ Init(); REP(i,0,n){ int x=a*i+b*(n-i); if(check(x)){ ans+=C [i]; if(ans>=P)ans-=P; } } cout<<ans<<endl; } }p70; struct p100{ LL Pow(LL x,LL y){ LL res=1; while(y>0){ if(y&1)(res*=x)%=P; x=x*x%P;y>>=1; } return res; } LL fac ; void solve(){ fac[0]=1; REP(i,1,n)fac[i]=fac[i-1]*i%P; LL ans=0; REP(i,0,n){ int x=a*i+b*(n-i); if(!check(x))continue; ans+=fac *Pow(fac[n-i],P-2)%P*Pow(fac[i],P-2)%P,ans%=P; } cout<<ans<<endl; } }p100; int main(){ // freopen("excellent.in","r",stdin); // freopen("excellent.out","w",stdout); cin>>a>>b>>n; if(n<=15)p40.solve(); else if(n<=1000)p70.solve(); else p100.solve(); return 0; }
num ——3803
思路:赤裸裸的dp,也比较好定义的——dp[i][j]表示上一个截点的位置为j,当前的数字串为j+1到i。但这样还不够(只有70),还需要后缀数组优化一下(kmp)。#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<queue> using namespace std; #define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++) #define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--) #define LL long long #define db double #define INF 0x3f3f3f3f #define inf 0x7fffffff #define mcl(a,b) memset(a,b,sizeof(a)) #define Sz(a) sizeof(a) #define pb push_back #define N 3004 #define P 1000000007 int n; char s ; int dp ; struct P80{ bool Cmp(int x,int y,int len){ while(len && s[x]==s[y])x++,y++,len--; if(len)return s[x]<s[y]; return 0; } void solve(){ int tmp; if(s[1]!='0')REP(i,1,n)dp[1][i]=1; REP(i,1,n)REP(j,i,n-1)if((tmp=dp[i][j]) && s[j+1]!='0'){ int len=j-i+1; if(j+len<=n && Cmp(i,j+1,len))(dp[j+1][j+len]+=tmp)%=P; REP(k,j+len+1,n)(dp[j+1][k]+=tmp)%=P; } int ans=0; REP(i,1,n)(ans+=dp[i] )%=P; cout<<ans<<endl; } }p80; struct p100{ int mark ; void Init(){ DREP(i,n,1){ DREP(j,n,1){ if(s[i]>s[j])mark[i][j]=i; else if(s[i]<s[j])mark[i][j]=0; else mark[i][j]=mark[i+1][j+1]; } } } void solve(){ Init(); REP(i,1,n)dp[1][i]=1; REP(i,2,n){ if(s[i]=='0')continue; for(int j=i,k=i-1;j<=n && k;j++,k--){ if(s[k]=='0')continue; if(mark[i][k] && mark[i][k]<=j)(dp[i][j]+=dp[k][i-1])%=P; else (dp[i][j+1]+=dp[k][i-1])%=P; } REP(j,i+1,n)(dp[i][j]+=dp[i][j-1])%=P; } LL ans=0; REP(i,1,n)(ans+=dp[i] )%=P; cout<<ans<<endl; } }p100; int main(){ // freopen("num.in","r",stdin); // freopen("num.out","w",stdout); cin>>n; scanf("%s",s+1); if(n<1000)p80.solve(); else p100.solve(); return 0; }
tree ——3804
思路:题意十分清晰,简而言之,就是其它点到两个被选定的点的最大距离。由链的情况——答案应为max(a−1,n−b,mid(b−a>>1))
引发我们思考,将树抽出一条链,也就是树的直径,那么答案同理,即a左边的所有点到a的最大距离,b右边的所有点到b的最大距离,以及a,b之间的所有点到a,b的最小值的最大值。这里两边的点都比较好处理,而中间的点需要再求出直径上a,b之间的点到其子树的每个点的距离,也就是max(min(dis[top]−dis[a],dis[b]−dis[top])+dep[x])
然而实现起来就比较困难了。
1.距离要倍增算,而且还要每个点向上跳和向下跳都要算出来。(蒟蒻我还没来得及写…)
2.也可以线段树来维护。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<queue> using namespace std; #define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++) #define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--) #define LL long long #define db double #define INF 0x3f3f3f3f #define inf 0x7fffffff #define mcl(a,b) memset(a,b,sizeof(a)) #define Sz(a) sizeof(a) #define pb push_back #define lson L,mid,p<<1 #define rson mid+1,R,p<<1|1 #define family tree[p],tree[p<<1],tree[p<<1|1] #define root 1,n,1 #define N 100000 int n,m; int A ,B ; int D ,son ,fa ,top ,sz ; vector<int>E ; void dfs1(int x,int f){ sz[x]=1; D[x]=D[f]+1; fa[x]=f; son[x]=0; REP(i,0,E[x].size()-1){ int y=E[x][i]; if(y==f)continue; dfs1(y,x); sz[x]+=sz[y]; if(sz[y]>sz[son[x]])son[x]=y; } } void dfs2(int x,int tp){ top[x]=tp; if(son[x])dfs2(son[x],tp); REP(i,0,E[x].size()-1){ int y=E[x][i]; if(y==fa[x] || y==son[x])continue; dfs2(y,y); } } int Lca(int a,int b){ while(top[a]!=top[b]){ if(D[top[a]]<D[top[b]])swap(a,b); a=fa[top[a]]; } return D[a]<D[b]?a:b; } struct plist{ int Index,ID[100012]; bool check(){ REP(i,1,n)if(E[i].size()>2)return 0; return 1; } void dfs(int x,int f){ ID[x]=++Index; REP(i,0,E[x].size()-1){ int V=E[x][i]; if(V==f) continue; dfs(V,x); } } void solve(){ int s=0; for(int i=1;i<=n;i++)if(E[i].size()==1){s=i;break;} Index=0; dfs(s,s); REP(i,1,m){ int a,b; int ans=0; a=ID[A[i]],b=ID[B[i]]; if(a>b) swap(a,b); ans=max(a-1,n-b); ans=max(ans,(b-a)>>1); printf("%d\n",ans); } } }p_list; struct p30{ void solve(){ dfs1(1,0); dfs2(1,1); REP(i,1,m){ int a=A[i],b=B[i]; int ans=0; REP(j,1,n){ int lca1=Lca(a,j),lca2=Lca(b,j); int s1=D[a]+D[j]-D[lca1]*2; int s2=D[b]+D[j]-D[lca2]*2; ans=max(ans,min(s1,s2)); } printf("%d\n",ans); } } }p30; int Mxval ; struct p100{ int d,Dx,Rx,s; int Id ,dis ,is_D ,Link ; struct Tree{ struct node{ int L,R,mx; }tree[N<<2]; void build(int L,int R,int p,int x){ tree[p].L=L,tree[p].R=R; if(L==R){ tree[p].mx=Mxval[L]+L*x; return; } int mid=(L+R)>>1; build(lson,x),build(rson,x); tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx); } int query(int L,int R,int p){ if(tree[p].L==L && tree[p].R==R)return tree[p].mx; int mid=(tree[p].L+tree[p].R)>>1; if(R<=mid)return query(L,R,p<<1); else if(L>mid)return query(L,R,p<<1|1); else return max(query(lson),query(rson)); } }Tree[2]; void dfs(int x,int f,int cost){ if(cost>d)d=cost,Dx=x; fa[x]=f; REP(i,0,E[x].size()-1){ int y=E[x][i]; if(y==f)continue; dfs(y,x,cost+1); } } int k; void Dfs(int x,int f,int cost){ Id[x]=k; dis[x]=cost; if(cost>Mxval[k])Mxval[k]=cost; REP(i,0,E[x].size()-1){ int y=E[x][i]; if(y==f || is_D[y])continue; Dfs(y,x,cost+1); } } void Setid(){ int a=Dx; while(a!=Rx){ is_D[a]=1; Link[++s]=a; a=fa[a]; } Link[++s]=a; is_D[a]=1; REP(i,1,s){ k=i; Dfs(Link[i],0,0); } } void solve(){ d=-1; dfs(1,0,0); Rx=Dx,d=-1; dfs(Rx,0,0); Setid(); Tree[0].build(1,s,1,1); Tree[1].build(1,s,1,-1); REP(i,1,m){ int a=A[i],b=B[i]; if(Id[b]<Id[a])swap(a,b); int x=(Id[a]+Id[b]+dis[b]-dis[a])/2; int ans=0; if(Id[a]==Id[b]){ ans=min(dis[a],dis[b])+Id[a]-1; ans=max(s+min(dis[a],dis[b])-Id[a],ans); printf("%d\n",ans); continue; }else { int tmp1=min(dis[a]+Id[a]-1,dis[b]+Id[b]-1); int tmp2=min(dis[a]+s-Id[a],dis[b]+s-Id[b]); ans=max(tmp1,tmp2); } if(Id[a]<min(Id[b],x))ans=max(ans,Tree[0].query(Id[a]+1,min(Id[b],x),1)-Id[a]+dis[a]); if(max(Id[a],x+1)<Id[b])ans=max(ans,Tree[1].query(max(Id[a],x+1),Id[b]-1,1)+Id[b]+dis[b]); printf("%d\n",ans); } } }p100; int main(){ // freopen("tree.in","r",stdin); // freopen("tree.out","w",stdout); cin>>n; REP(i,1,n-1){ int a,b; scanf("%d%d",&a,&b); E[a].pb(b);E[b].pb(a); } cin>>m; REP(i,1,m)scanf("%d%d",&A[i],&B[i]); // if(n<=2000)p30.solve(); // else if(p_list.check())p_list.solve(); // else p100.solve(); p100.solve(); return 0; }
小结:今天考得不是很好,第1题逆元没想到,第3题链写错了…(代码功底还要加强呀!)
相关文章推荐
- 2017/7/29 离线赛 总结
- 星星之火,可以燎原!------------完整的ubuntu镜像源/本地源/更新源/离线升级包!制作总结
- 2017.10.30离线赛总结
- Xmpp问题总结:XMPP离线管理
- 20171009离线赛总结
- 2017-10-9离线赛总结
- Hybrid APP的离线存储总结
- 17.7.26离线赛比赛总结
- Google Docs离线功能的简单总结
- 2017-9-28离线赛总结
- 2017.10.19离线赛总结
- LCA 最近公共祖先 tarjan离线 总结 结合3个例题
- 2017.10.27离线赛总结
- 2017-10-29离线赛总结
- 离线赛20171007总结
- 2017-10-8离线赛总结
- 2017-11-3离线赛总结
- 2017-10-12离线赛总结
- 2017.10.11离线赛总结
- 基于网上文章总结的ubuntu 12.04.04离线软件安装方法