清北考前刷题da5下午好
/* (4,1)*(3,1)*(2,1)的话1变成2然后一直是2 2变成1然后变成3 3变成1然后变成4 4变成1 */ #include<iostream> #include<cstdio> #include<cstring> #define N 1007 using namespace std; int n,m,p,k,ans,cnt,tmp; int a[N],pos[N]; struct node{ int len,q[N]; }s[N]; inline int read() { int x=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int main() { freopen("rotate.in","r",stdin); freopen("rotate.out","w",stdout); n=read();p=read();k=read(); for(int i=1;i<=n;i++) a[i]=i,pos[i]=i; for(int i=p;i>=1;i--) { s[i].len=read(); for(int j=1;j<=s[i].len;j++) s[i].q[j]=read(); } for(int i=1;i<=p;i++) { for(int j=2;j<=s[i].len;j++) { int x=s[i].q[j],y=s[i].q[1]; swap(a[pos[x]],a[pos[y]]); swap(pos[x],pos[y]); } } for(int i=1;i<=n;i++) printf("%d ",a[i]); return 0; }
/*
60线段树
*/
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mod 1000000007 #define N 1003 #define ll long long using namespace std; int n,a,b,c,d,ans,cnt; int And[N][N],Or[N][N]; int s[N]; struct tree{ int l,r,sum1,sum2; }tr[N<<2]; bool cmp(int a,int b){return a>b;} inline int read() { int x=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } inline void pushup(int k) { tr[k].sum1=tr[k<<1].sum1 & tr[k<<1|1].sum1; tr[k].sum2=tr[k<<1].sum2 | tr[k<<1|1].sum2; } void build(int k,int l,int r) { tr[k].l=l;tr[k].r=r; if(l==r) { tr[k].sum1=read(); tr[k].sum2=tr[k].sum1; return; } int mid=l+r>>1; build(k<<1,l,mid);build(k<<1|1,mid+1,r); pushup(k); } int query1(int k,int l,int r) { if(tr[k].l==l && tr[k].r==r) return tr[k].sum1; int mid=tr[k].l+tr[k].r>>1; pushup(k); if(r<=mid) return query1(k<<1,l,r); else if(l>mid) return query1(k<<1|1,l,r); else return query1(k<<1,l,mid) & query1(k<<1|1,mid+1,r); } int query2(int k,int l,int r) { if(tr[k].l==l && tr[k].r==r) return tr[k].sum2; int mid=tr[k].l+tr[k].r>>1; pushup(k); if(r<=mid) return query2(k<<1,l,r); else if(l>mid) return query2(k<<1|1,l,r); else return query2(k<<1,l,mid) | query2(k<<1|1,mid+1,r); } int main() { freopen("range.in","r",stdin); freopen("range.out","w",stdout); n=read();a=read();b=read();c=read();d=read(); build(1,1,n); for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) And[i][j]=query1(1,i,j),Or[i][j]=query2(1,i,j); for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) if(And[i][j]<=b && And[i][j]>=a && Or[i][j]<=d && Or[i][j]>=c) { ans++; if(ans>mod) ans-=mod; } printf("%d\n",ans); return 0; }
/* 有单调性 枚举左端点,二分右端点,ST表处理,计算答案。 */ #include<iostream> #include<cstdio> #include<cstring> #include <cmath> #define N 100007 #define ll long long #define mod 1000000007 using namespace std; int n,a,b,c,d,ans; int st1[N][22],st2[N][22]; int s[N];ll cnt; inline int read() { int x=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int query1(int l,int r) { int len=r-l+1,p=log2(len); return st1[l][p] & st1[r-(1<<p)+1][p]; } int query2(int l,int r) { int len=r-l+1,p=log2(len); return st2[l][p] | st2[r-(1<<p)+1][p]; } int main() { freopen("range.in","r",stdin); freopen("range.out","w",stdout); n=read();a=read();b=read();c=read();d=read(); for(int i=1;i<=n;i++) s[i]=read(),st1[i][0]=st2[i][0]=s[i]; for(int j=1;j<=20;j++) for(int i=1;i+(1<<j)-1<=n;i++) st1[i][j]=st1[i][j-1] & st1[i+(1<<(j-1))][j-1], st2[i][j]=st2[i][j-1] | st2[i+(1<<(j-1))][j-1]; int sum1,sum2,L,R,mid;ans=0,cnt=0; for(int i=1;i<=n;i++) { sum1=sum2=s[i]; for(int j=i;j<=n;j++) { sum1=query1(i,j);sum2=query2(i,j); L=j,R=n+1; while(L<=R) { mid=L+R>>1; if(query1(i,mid)==sum1 && query2(i,mid)==sum2) ans=mid,L=mid+1; else R=mid-1; } if(a<=sum1 && sum1<=b && c<=sum2 && sum2<=d) cnt+=ans-j+1;j=ans; } } printf("%I64d\n",cnt%mod); return 0; }
/* 不先考虑k个,1~n先都考虑。 按子树为单位树形dp f[x][j]表示以x为根的子树有j个果子方案数。 x显然果子必须拿,其他的果子需要分配。 但如果有很多孩子,那么挨个分配会T。 所以考虑树形dp常用策略把子树编号。 考虑孩子的每个前缀分多少,还剩多少。 就是每个前缀的max而不是子集的max。 所以要设计前缀的状态:g[i][j]表示以i为结尾的前缀分j个果子的方案数。 就转化为了背包问题。 但直接转移是n^3的,考虑优化。 可以看出枚举每个前缀是不必要的。 从根节点递归到子节点往上反的时候子节点的状态先继承父节点的状态,然后进行转移。 这样每个点都会从左到右把它儿子的每个前缀计算答案并取max。详见代码。 */ #include<iostream> #include<cstdio> #include<cstring> #define mod 1000000007 #define N 1007 #define ll long long using namespace std; int n,m,ans,cnt; ll f[N][N],p[N]; int val[N],head[N]; struct edge{ int u,v,net; }e[N<<1]; inline int read() { int x=0,f=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } inline void add(int u,int v) { e[++cnt].v=v;e[cnt].net=head[u];head[u]=cnt; } int dp(int u,int fa) { int siz=1; for(int i=head[u];i;i=e[i].net) { int v=e[i].v; if(v==fa) continue; for(int j=0;j<=n-val[v];j++) f[v][j+val[v]]=f[u][j]; int tmp=dp(v,u); for(int j=0;j<=n;j++) f[u][j]=(p[tmp-1]*f[u][j]%mod+f[v][j])%mod; siz+=tmp; }return siz; } int main() { int x,y,z; n=read();m=read();p[0]=1; for(int i=1;i<=n;i++)p[i]=(p[i-1]*2)%mod; for(int i=1;i<=n;i++) val[i]=read(); for(int i=1;i<n;i++) { x=read();y=read(); add(x,y);add(y,x); } f[1][val[1]]=1;dp(1,0); printf("%d\n",int(f[1][m])); return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。