好多考试....
11.01 早上考试
T1 虎...
这题真是虎,大力才结论,水掉了...
每一次翻转一定是只翻转白色连续的一段,然后dfs一遍就行了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } const int N=1000006; int first[N],nt[N<<1],ver[N<<1],clo[N<<1],fina[N<<1],e; void addbian(int u,int v,int _clo,int _fina) { ver[e]=v; clo[e]=_clo; fina[e]=_fina; nt[e]=first[u]; first[u]=e++; } int n; int ans; int fa[N],g[N]; void dfs(int x) { g[x]=0; int i,sum=0; for(i=first[x];i!=-1;i=nt[i]) if(ver[i]!=fa[x]) { fa[ver[i]]=x; dfs(ver[i]); if(!fina[i]) { if(g[ver[i]]) ++sum; } else { if(!g[ver[i]]) { if(!clo[i]) ++sum; } else { if(clo[i]) ++ans; else ++sum; } } } ans+=(sum>>1); if(sum&1) g[x]=1; else g[x]=0; if(x==1&&g[x]) ++ans; } int main(){ //freopen("T1.in","r",stdin); //freopen("tiger.in","r",stdin); //freopen("tiger.out","w",stdout); rint i; int tin1,tin2,tin3; mem(first,-1); read(n); for(i=2;i<=n;++i) { read(tin1); read(tin2); read(tin3); if(tin2!=0) tin2=1; if(tin3!=0) tin3=1; addbian(i,tin1,tin2,tin3); addbian(tin1,i,tin2,tin3); } dfs(1); cout<<ans; }
T2 阴阳
30分暴搜
打表再来30分
正解是dp
发现黑白一定是分成两块,并且边界是单调的
分黑白在两边和边界单调下降什么的搞就行了
最后去掉重
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } inline void readchar(char &x) { x=getchar(); while(x!='B'&&x!='W'&&x!='?') x=getchar(); } const int mod=1e9+7; int n,m; char v[1006][1006]; ll f[1006][1006]; int wbl[1006],wbr[1006],bwl[1006],bwr[1006]; int t1[1006],t2[1006],t3[1006],t4[1006]; ll dp() { rint i,j,k; int l,r,tt; ll sum,an=0; for(i=1;i<=n;++i) { r=0; l=m; while(r<=m&&v[i][r]!='W') ++r; --r; while(l>=0&&v[i][l]!='B') --l; if(l<0) ++l; bwl[i]=l; bwr[i]=r; r=0; l=m; while(r<=m&&v[i][r]!='B') ++r; --r; while(l>=0&&v[i][l]!='W') --l; if(l<0) ++l; wbl[i]=l; wbr[i]=r; } // bl|wh mem(f,0); l=bwl[1]; r=bwr[1]; //printf("l=%d r=%d\n",l,r); for(j=l;j<=r;++j) f[1][j]=1; for(i=2;i<=n;++i) { l=bwl[i]; r=bwr[i]; //printf("l=%d r=%d\n",l,r); sum=0; for(k=r+1;k<=m;++k) sum=(sum+f[i-1][k])%mod; for(j=r;j>=l;--j) { sum=(sum+f[i-1][j])%mod; f[i][j]=sum; } } //printf("pr1an=%lld\n",an); for(j=0;j<=m;++j) an=(an+f[n][j])%mod; //printf("ho1an=%lld\n",an); // bl\wh mem(f,0); l=bwl[1]; r=bwr[1]; for(j=l;j<=r;++j) f[1][j]=1; for(i=2;i<=n;++i) { l=bwl[i]; r=bwr[i]; sum=0; for(k=0;k<l;++k) sum=(sum+f[i-1][k])%mod; for(j=l;j<=r;++j) { sum=(sum+f[i-1][j])%mod; f[i][j]=sum; } } for(j=0;j<=m;++j) an=(an+f[n][j])%mod; // wh/bl mem(f,0); l=wbl[1]; r=wbr[1]; for(j=l;j<=r;++j) f[1][j]=1; for(i=2;i<=n;++i) { l=wbl[i]; r=wbr[i]; sum=0; for(k=r+1;k<=m;++k) sum=(sum+f[i-1][k])%mod; for(j=r;j>=l;--j) { sum=(sum+f[i-1][j])%mod; f[i][j]=sum; } } for(j=0;j<=m;++j) an=(an+f[n][j])%mod; // wh\bl mem(f,0); l=wbl[1]; r=wbr[1]; for(j=l;j<=r;++j) f[1][j]=1; for(i=2;i<=n;++i) { l=wbl[i]; r=wbr[i]; sum=0; for(k=0;k<l;++k) sum=(sum+f[i-1][k])%mod; for(j=l;j<=r;++j) { sum=(sum+f[i-1][j])%mod; f[i][j]=sum; } } for(j=0;j<=m;++j) an=(an+f[n][j])%mod; // wh\bl // wh/bl // bl\wh // bl/wh //int wbmnl1=0,wbmxr1=m,bwmnl1=0,bwmxr1=m; //int wbmnl2=0,wbmxr2=n,bwmnl2=0,bwmxr2=n; int l0,r0; int whnum=0,blnum=0; l=0; r=m; for(i=1;i<=n;++i) { if(l<wbl[i]) l=wbl[i]; if(r>wbr[i]) r=wbr[i]; } //printf("l=%d r=%d\n",l,r); for(i=l;i<=r;++i) t1[i]+=2; if(l==0) blnum+=1; if(r==m) whnum+=1; l=0; r=m; for(i=1;i<=n;++i) { if(l<bwl[i]) l=bwl[i]; if(r>bwr[i]) r=bwr[i]; } //printf("l=%d r=%d\n",l,r); for(i=l;i<=r;++i) t2[i]+=2; if(l==0) whnum+=1; if(r==m) blnum+=1; l0=0; r0=n; for(j=1;j<=m;++j) { l=n; r=0; while(l>=0&&v[l][j]!='B') --l; if(l<0) ++l; while(r<=n&&v[r][j]!='W') ++r; --r; if(l0<l) l0=l; if(r0>r) r0=r; } //printf("l0=%d r0=%d\n",l0,r0); for(i=l0;i<=r0;++i) t3[i]+=2; if(l0==0) whnum+=1; if(r0==n) blnum+=1; l0=0; r0=n; for(j=1;j<=m;++j) { l=n; r=0; while(l>=0&&v[l][j]!='W') --l; if(l<0) ++l; while(r<=n&&v[r][j]!='B') ++r; --r; if(l0<l) l0=l; if(r0>r) r0=r; } //printf("l0=%d r0=%d\n",l0,r0); for(i=l0;i<=r0;++i) t4[i]+=2; if(l0==0) blnum+=1; if(r0==n) whnum+=1; //printf("prpran=%lld\n",an); if(blnum) an=(an-blnum+1+mod)%mod; if(whnum) an=(an-whnum+1+mod)%mod; //printf("pran=%lld\n",an); for(i=1;i<m;++i) { if(t1[i]) an=(an-t1[i]+1+mod)%mod; if(t2[i]) an=(an-t2[i]+1+mod)%mod; } for(i=1;i<n;++i) { if(t3[i]) an=(an-t3[i]+1+mod)%mod; if(t4[i]) an=(an-t4[i]+1+mod)%mod; } //printf("an=%lld\n",an); return (an%mod+mod)%mod; } int main(){ //freopen("T2.in","r",stdin); //freopen("T2.out","w",stdout); rint i,j; read(n); read(m); for(i=1;i<=n;++i) for(j=1;j<=m;++j) readchar(v[i][j]); printf("%lld",dp()); }
T3 山洞
真正题意:
走m次,第i次走i步,又正好在第m次走回来的方案数
注意两个方案不同当且仅当走过的山洞排列有一个不同
直接矩阵乘,循环矩阵$O(n^2logm)$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int mod=1e9+7; int n,m; ll f[1006],a1[1006][1006],a[1006][1006],t[1006]; ll dp() { rint i,j,k,p; int t1,t2,ci; for(i=0;i<n;++i) a[i][i]=1; for(p=1;p<=n;++p) { for(i=0;i<n;++i) { t[i]=0; t1=(i-p+n)%n; t[i]=(t[i]+a[0][t1])%mod; t2=(i+p)%n; if(t1!=t2) t[i]=(t[i]+a[0][t2])%mod; } for(i=0;i<n;++i) a[0][i]=t[i]; /*for(i=0;i<n;++i) printf("%lld ",a[0][i]); printf("\n");*/ } for(i=1;i<n;++i) { a[i][0]=a[i-1][n-1]; for(j=1;j<n;++j) a[i][j]=a[i-1][j-1]; } /*printf("\n"); for(i=0;i<n;++i) { for(j=0;j<n;++j) printf("%lld ",a[i][j]); printf("\n"); } printf("\n");*/ ci=m/n; m=m-n*ci; //printf("ci=%d\n",ci); f[0]=1; while(ci) { if(ci&1) { for(i=0;i<n;++i) { t[i]=0; for(k=0;k<n;++k) t[i]=(t[i]+f[k]*a[k][i]%mod)%mod; } for(i=0;i<n;++i) f[i]=t[i]; } for(i=0;i<n;++i) { t[i]=0; for(k=0;k<n;++k) t[i]=(t[i]+a[0][k]*a[k][i]%mod)%mod; } for(i=0;i<n;++i) a[0][i]=t[i]; for(i=1;i<n;++i) { a[i][0]=a[i-1][n-1]; for(j=1;j<n;++j) a[i][j]=a[i-1][j-1];; } ci>>=1; } for(p=1;p<=m;++p) { for(i=0;i<n;++i) { t[i]=0; t1=(i-p+n)%n; t[i]=(t[i]+f[t1])%mod; t2=(i+p)%n; if(t1!=t2) t[i]=(t[i]+f[t2])%mod; } for(i=0;i<n;++i) f[i]=t[i]; } return f[0]; } int main(){ //freopen("T3.in","r",stdin); //freopen("T3.out","w",stdout); read(n); read(m); printf("%lld",dp()); }
11.02 晚上
T1 set
无解是骗人的...
求出在mod n 意义下的前缀和,算上$sum_0$一共有最多有n+1个取值
一定有两个相等,输出两个之间的ans即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define ll long long #define rint register int #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; const int N=1000006; inline void read(int &x) { x=0; int f=1;char ch=getchar(); while(ch<'0'|ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} x*=f; } int n; int v[N],pr[N]; int pos[N]; int main(){ rint i,j; read(n); for(i=1;i<=n;++i) read(v[i]); mem(pos,-1); pos[0]=0; for(i=1;i<=n;++i) { pr[i]=(pr[i-1]+v[i])%n; if(pos[pr[i]]!=-1) { printf("%d\n",i-pos[pr[i]]); for(j=pos[pr[i]]+1;j<=i;++j) printf("%d ",j); printf("\n"); break; } pos[pr[i]]=i; } }
T2 read
我还以为是什么高级数学题
结果...
很显然是让求最多出现次数的书出现了多少次
那么先 利用有用的最大出现次数一定>$\frac{n+1}{2}$的性质
设 id=0,cnt=0
扫到cnt=0,就id=当前位置值,cnt=1
if(cnt>0)
如果当前v不等于id,--cnt
否则++cnt
扫到最大值的编号id,但是cnt不准
所以再扫一遍,求出出现次数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define ll long long #define rint register int #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; const int N=1000006; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'|q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } int n,m,K; int c[1006],X[1006],Y[1006],Z[1006]; int main(){ rint i,j; read(m); read(K); for(i=1;i<=m;++i) read(c[i]); for(i=1;i<=m;++i) read(X[i]); for(i=1;i<=m;++i) read(Y[i]); for(i=1;i<=m;++i) read(Z[i]); int maxp=(1<<K)-1,id=-2e9,cnt=0,an; n=0; ll las; for(i=1;i<=m;++i) { ++n; las=X[i]; if(cnt==0) id=las,cnt=1; else { if(las!=id) --cnt; else ++cnt; } for(j=1;j<c[i];++j) { las=(las*Y[i]+Z[i])&maxp; ++n; if(cnt==0) id=las,cnt=1; else { if(las!=id) --cnt; else ++cnt; } } } n=0; cnt=0; for(i=1;i<=m;++i) { ++n; las=X[i]; if(las==id) ++cnt; for(j=1;j<c[i];++j) { las=(las*Y[i]+Z[i])&maxp; ++n; if(las==id) ++cnt; } } an=cnt-1-(n-cnt); if(an<0) an=0; cout<<an; }
T3 race
考试直接上01trie,然后就懵逼了...
正解:
把求$x^2$转化成求前面比他大的数两两配对的对数
然后发现在01trie上行走,每到一位有$2^{m-1}$天左边比右边大,有$2^{m-1}$天右边比左边大
设当前到了第i个人,$f_i$为到了01trie上第i位 要走儿子的对立儿子的size
$$ans=\sum_{2*f_i*f_k*2^{m-2}} 的异或和 $$
$2*f_i*f_k$是在枚举有序对
$2^{m-2}$是在求交集的个数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <iostream> #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define rint register int using namespace std; const int mod=1e9+7; inline void read(int &x) { x=0; int ff=1; char q=getchar(); while(q<'0'||q>'9') { if(q=='-') ff=-1; q=getchar(); } while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); x*=ff; } const int N=200006; int n,m; int A[N]; ll an; int cnt[42]; ll f[2][2006]; struct trie { int sum; trie *ch[2]; trie(){sum=0;ch[0]=ch[1]=NULL;} }tong[N*30],*root; int size; void add(int vv) { ++root->sum; trie *now=root; int i,tt; for(i=m-1;~i;--i) { tt=((1<<i)&vv)>>i; if(now->ch[tt]==NULL) now->ch[tt]=&tong[size++]; now=now->ch[tt]; ++now->sum; } } void dfs(trie *x,ll pr,ll sum) { if(x->ch[0]==NULL&&x->ch[1]==NULL) { an^=sum; return ; } int tt; if(x->ch[0]!=NULL) { tt=(x->ch[1]==NULL?0:x->ch[1]->sum); dfs(x->ch[0],(pr+tt)%mod,(sum+1LL*tt*(pr+tt)%mod*(1<<(m-1))%mod)%mod); } if(x->ch[1]!=NULL) { tt=(x->ch[0]==NULL?0:x->ch[0]->sum); dfs(x->ch[1],(pr+tt)%mod,(sum+1LL*tt*(pr+tt)%mod*(1<<(m-1))%mod)%mod); } } int main(){ //freopen("T3.in","r",stdin); //freopen("T3.out","w",stdout); rint i,j,k; int tt,sum,now,pr,q1; read(n); read(m); for(i=1;i<=n;++i) read(A[i]); root=&tong[size++]; for(i=1;i<=n;++i) add(A[i]); dfs(root,0,0); cout<<an; }
11.02早上
T1 hanoi
它不一定是在中间m-2个柱子上均匀铺开最优...
$f_{i,j}$ 表示i个盘子j个柱子的最小次数
$$ f_{i,j}=min(f_{k,j}+f_{i-k,j-1})$$
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #define rint register int using namespace std; void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } int n,m; ll f[106][106]; int main(){ rint i,j,k; read(n); read(m); mem(f,127); for(j=3;j<=m;++j) f[1][j]=1; for(i=2;i<=n;++i) f[i][3]=f[i-1][3]*2+1; for(i=2;i<=n;++i) for(j=4;j<=m;++j) for(k=1;k<i;++k) f[i][j]=min(f[i][j],f[k][j]*2+f[i-k][j-1]); cout<<f[n][m]; }
T2 rank
贪心就行了
如果rank和rank+1后面的位置仍然满足大小关系
说明这一位可以相等,解决纠纷留到下一次
否则必须++
最后大于26个取值就不合法...
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #define rint register int using namespace std; void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int N=200006; int n; int ran[N],pos[N]; int an[N]; int main(){ rint i; read(n); for(i=1;i<=n;++i) read(ran[i]),pos[ran[i]]=i; an[pos[1]]=0; for(i=1;i<n;++i) { if(ran[pos[i]+1]<ran[pos[i+1]+1]) an[pos[i+1]]=an[pos[i]]; else an[pos[i+1]]=an[pos[i]]+1; } int ff=0; for(i=1;i<=n;++i) if(an[i]>=26) ff=1; if(ff) puts("-1"); else for(i=1;i<=n;++i) printf("%c",an[i]+'a'); }
T3 tree
又是两遍dfs的傻逼题...
$f_{x}$ 表示从x走到父亲的期望次数
转移方程经过一波化简后就会变成整数
没有分数...
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long #define rint register int using namespace std; void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int mod=1e9+7; const int N=100006; int first[N],nt[N<<1],ver[N<<1],e; void addbian(int u,int v) { ver[e]=v; nt[e]=first[u]; first[u]=e++; } int n,Q; int maxk; ll f[N],g[N],sumf[N][21],sumg[N][21]; int st[N][21]; int fa[N],dep[N]; void dfs1(int x) { f[x]=1; int i; for(i=first[x];i!=-1;i=nt[i]) if(ver[i]!=fa[x]) { fa[ver[i]]=x; dep[ver[i]]=dep[x]+1; dfs1(ver[i]); f[x]=(f[x]+f[ver[i]]+1)%mod; } } void dfs2(int x) { int i; for(i=first[x];i!=-1;i=nt[i]) if(ver[i]!=fa[x]) { if(fa[x]!=-1) g[ver[i]]=1; g[ver[i]]=(g[ver[i]]+g[x]+1+(f[x]-1-f[ver[i]]-1))%mod; dfs2(ver[i]); } } void ST() { rint i; int j; while((1<<maxk)<=n) ++maxk; --maxk; mem(st,-1); for(i=1;i<=n;++i) st[i][0]=fa[i],sumf[i][0]=f[i],sumg[i][0]=g[i]; for(j=1;(1<<j)<=n;++j) for(i=1;i<=n;++i) if(st[i][j-1]!=-1) st[i][j]=st[st[i][j-1]][j-1], sumf[i][j]=(sumf[i][j-1]+sumf[st[i][j-1]][j-1])%mod, sumg[i][j]=(sumg[i][j-1]+sumg[st[i][j-1]][j-1])%mod; } int LCA(int x,int y) { if(dep[x]<dep[y]) x^=y,y^=x,x^=y; int j; for(j=maxk;~j;--j) if(dep[x]-(1<<j)>=dep[y]) x=st[x][j]; if(x==y) return x; for(j=maxk;~j;--j) if(st[x][j]!=-1&&st[x][j]!=st[y][j]) x=st[x][j],y=st[y][j]; return fa[x]; } ll getf(int x,int y) { if(dep[x]<=dep[y]) return 0; ll an=0; int j; for(j=maxk;~j;--j) if(dep[x]-(1<<j)>=dep[y]) an=(an+sumf[x][j])%mod,x=st[x][j]; return an; } ll getg(int x,int y) { if(dep[x]<=dep[y]) return 0; ll an=0; int j; for(j=maxk;~j;--j) if(dep[x]-(1<<j)>=dep[y]) an=(an+sumg[x][j])%mod,x=st[x][j]; return an; } int main(){ //freopen("T3.in","r",stdin); rint i; int tin1,tin2,tt; mem(first,-1); read(n); read(Q); for(i=1;i<n;++i) { read(tin1); read(tin2); addbian(tin1,tin2); addbian(tin2,tin1); } fa[1]=-1; dfs1(1); dfs2(1); ST(); /*printf("\n"); for(i=1;i<=n;++i) printf("%lld ",f[i]); printf("\n"); for(i=1;i<=n;++i) printf("%lld ",g[i]); printf("\n");*/ for(i=1;i<=Q;++i) { read(tin1); read(tin2); tt=LCA(tin1,tin2); //printf("%d %d %d\n",tin1,tin2,tt); printf("%lld\n",(getf(tin1,tt)+getg(tin2,tt))%mod); } }
还有一些,不想写了....
最近老是犯一些智障错误
正解不会,暴力打挂...
我也很无奈啊...