A.
有点像学军中学的一道NOIP模拟赛的题。因为插入的顺序唯一,然后就完了。。。
具体操作是在线段树上二分,然后区间赋值1等等。。。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define maxv 100500 #define maxe 200500 using namespace std; int n,q,x,y,g[maxv],nume=1,w[maxv],fw[maxv],dis[maxv],cnt=0,tot=0,anc[maxv][20],val[maxv]; int ls[maxv<<2],rs[maxv<<2],lazy[maxv<<2],sum[maxv<<2],root,tr_root; int t=0; struct status { int id,val; status (int id,int val):id(id),val(val) {} status () {} }; vector <status> v[maxv]; struct edge { int v,nxt; }e[maxe]; bool cmp(status x,status y) {return x.val<y.val;} void addedge(int u,int v) { e[++nume].v=v;e[nume].nxt=g[u]; g[u]=nume; } void dfs1(int x) { val[x]=x; for (int i=g[x];i;i=e[i].nxt) { int v=e[i].v; if (v!=anc[x][0]) { anc[v][0]=x;dis[v]=dis[x]+1; dfs1(v); val[x]=min(val[x],val[v]); } } } void dfs2(int x) { for (int i=g[x];i;i=e[i].nxt) { int vs=e[i].v; if (vs==anc[x][0]) continue; v[x].push_back(status(vs,val[vs])); } sort(v[x].begin(),v[x].end(),cmp); for (int i=0;i<v[x].size();i++) dfs2(v[x][i].id); w[x]=++cnt;fw[cnt]=x; } void build(int &now,int left,int right) { now=++tot;sum[now]=lazy[now]=0; if (left==right) return; int mid=(left+right)>>1; build(ls[now],left,mid); build(rs[now],mid+1,right); } void pushdown(int now,int left,int right) { if (!lazy[now]) return; lazy[ls[now]]=lazy[rs[now]]=1;lazy[now]=0; int mid=(left+right)>>1; sum[ls[now]]=mid-left+1;sum[rs[now]]=right-mid; } int modify1(int now,int left,int right,int k) { pushdown(now,left,right); if (left==right) {sum[now]=1;return fw[left];} int mid=(left+right)>>1,r=(mid-left+1-sum[ls[now]]),ret; if (k>r) sum[ls[now]]=mid-left+1,lazy[ls[now]]=1; if (k>r) ret=modify1(rs[now],mid+1,right,k-r); else ret=modify1(ls[now],left,mid,k); sum[now]=sum[ls[now]]+sum[rs[now]]; return ret; } int ask(int now,int left,int right,int pos) { if (!pos) return 0; pushdown(now,left,right); if (left==right) return sum[now]; int mid=(left+right)>>1; if (pos<=mid) return ask(ls[now],left,mid,pos); else return ask(rs[now],mid+1,right,pos); } void modify2(int now,int left,int right,int pos) { pushdown(now,left,right); if (left==right) {sum[now]=0;return;} int mid=(left+right)>>1; if (pos<=mid) modify2(ls[now],left,mid,pos); else modify2(rs[now],mid+1,right,pos); sum[now]=sum[ls[now]]+sum[rs[now]]; } void work2() { int reg=y; for (int e=19;e>=0;e--) { int ret=ask(root,1,n,w[anc[y][e]]); if (ret) y=anc[y][e]; } modify2(root,1,n,w[y]); printf("%d\n",dis[reg]-dis[y]); } int main() { scanf("%d%d",&n,&q); for (int i=1;i<=n;i++) { scanf("%d",&x); if (!x) tr_root=i; else {addedge(x,i);addedge(i,x);} } dfs1(tr_root);dfs2(tr_root); for (int e=1;e<=19;e++) for (int i=1;i<=n;i++) anc[i][e]=anc[anc[i][e-1]][e-1]; build(root,1,n); for (int i=1;i<=q;i++) { scanf("%d%d",&x,&y); if (x==1) printf("%d\n",modify1(root,1,n,y)); else work2(); } return 0; }
B.
本来以为要用什么奇怪的自动机等等等等,然后。。。。
设这个数位置是n。奇数长度?a[n]!=a[n-2]。否则?a[n]!=a[n-1]。
然后数位dp一波就完了。。。
注意判0。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; long long a,b,dp[20][10][10],ret=0,bit[20]; void getbit(long long x) { ret=0; while (x) { bit[++ret]=x%10; x/=10; } } long long dfs(long long now,long long pre2,long long pre1,bool flag) { if (!now) return 1; if ((!flag) && (pre2!=-1) && (pre1!=-1) && (dp[now][pre2][pre1])) return dp[now][pre2][pre1]; long long ret=0,up=flag?bit[now]:9; for (long long i=0;i<=up;i++) { if ((i!=pre2) && (i!=pre1)) ret+=dfs(now-1,pre1,i,flag && (i==bit[now])); } if ((!flag) && (pre2!=-1) && (pre1!=-1)) dp[now][pre1][pre2]=ret; return ret; } long long ask(long long x) { if (x==-1) return 0; getbit(x);long long ans=0; for (long long i=1;i<=ret-1;i++) for (long long j=1;j<=9;j++) ans+=dfs(i-1,-1,j,0); for (long long i=1;i<=bit[ret]-1;i++) ans+=dfs(ret-1,-1,i,0); ans+=dfs(ret-1,-1,bit[ret],1); return ans; } int main() { scanf("%lld%lld",&a,&b); if (!a) {a++;printf("%lld\n",ask(b)-ask(a-1)+1);} else printf("%lld\n",ask(b)-ask(a-1)); return 0; }
C.
m>n?肯定多解。。。
m<n?废话。。。
m=n?环套树。。。然后直接按环上解方程就行了。。。。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 100500 #define maxe 1000050 using namespace std; int n,m,x,y,c[maxv],g[maxv],nume=1,val[maxe],d[maxv]; int top=0,flag2,flag3; bool vis[maxv],rol[maxv],flag1,flag4; struct edge { int v,nxt; }e[maxe]; struct status { int id,id1,id2,val; status (int id,int id1,int id2,int val):id(id),id1(id1),id2(id2),val(val) {} status () {} }s[maxv]; bool cmp(status x,status y) {return <;} void addedge(int u,int v) { e[++nume].v=v;e[nume].nxt=g[u]; g[u]=nume; } void dfs1(int x,int fath,int fath_e) { int ret=0; for (int i=g[x];i;i=e[i].nxt) { int v=e[i].v; if (v==fath) continue; dfs1(v,x,i);ret-=val[i>>1]; } val[fath_e>>1]=c[x]+ret; } void dfs2(int x,int fath_e) { vis[x]=true; for (int i=g[x];i;i=e[i].nxt) { int v=e[i].v; if ((vis[v]) && (i!=(fath_e^1))) { s[++top]=status(x,i>>1,fath_e>>1,c[x]); flag1=1;flag2=v;flag3=i;rol[x]=true; return; } if (vis[v]) continue; dfs2(v,i); if (flag1) { if (flag4) return; rol[x]=true; if (x!=flag2) s[++top]=status(x,i>>1,fath_e>>1,c[x]); else {s[++top]=status(x,i>>1,flag3>>1,c[x]);flag4=1;} return; } } return; } void work1() { dfs1(1,1,0); for (int i=1;i<=m;i++) printf("%d\n",val[i]<<1); return; } void work2() { for (int i=1;i<=n;i++) if (d[i]==1) {dfs2(i,0);break;} if (!(top&1)) {printf("0\n");return;} for (int i=1;i<=n;i++) { if (!rol[i]) continue; for (int j=g[i];j;j=e[j].nxt) { int v=e[j].v; if (rol[v]) continue; dfs1(v,i,j);c[i]-=val[j>>1]; } } int ret=0; for (int i=1;i<=top-1;i++) { if (i&1) ret+=c[s[i].id]; else ret-=c[s[i].id]; } val[s[1].id1]=(ret+c[s[top].id])/2; for (int i=1;i<=top-1;i++) val[s[i].id2]=c[s[i].id]-val[s[i].id1]; for (int i=1;i<=m;i++) printf("%d\n",val[i]<<1); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&c[i]); for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); addedge(x,y);addedge(y,x); d[x]++;d[y]++; } if (m>n) printf("0\n"); else if (m<n) work1(); else work2(); return 0; }
怎么说呢?。。。三道题都是,只要点出了它的核心都很简单。那么重点就是那一点点思维。