传送门:然而并没有...
这两天测试状态比较奇怪,前面1.5h-2h完全不知所措,一脸茫然,感觉自己吃枣药丸
后面才发现有很多题可捉的,并没有想象的那么难,但是时间已经不充裕了...
R2D2
T1:不知所措数学题
一开始总想着有什么DP可以拿一些部分分
然而连30分DP都不会....
咦,好像有大样例
那就找一发规律
妈呀真是2^(nk)
快速幂完事....
考完冷静了一下发现还是比较容易证的
首先n位每位相互独立,所以可以只考虑一位
设f[k]表示k*k的三角形的方案数
考虑f[k+1]怎么递推
如果最左下角的数是0,那么最后一行已经确定了,都会是0
而且不会对上面的k*k的三角形有影响,所以方案数是f[k]
如果是1,同理,最左边一行已经确定了,都必须是1
而且也不会对右边的k*k的三角形有影响,所以方案数是f[k]
所以f[k+1]=2*f[k]
所以一位的答案就是2^k
n位乘起来就好了,答案就是2^(nk)
T2:数据结构题?
一看到这题我就觉得是数据结构题,然而想来想去并不知道怎么维护....于是弃疗了
后来我才发现一个显然的性质
就是最大和最小一定取在端点,不然不是最优
然后我们就可以分数规划了
情况有点多
假设i是右端点,j是左端点
假设a[i]为max,a[j]为min
那么(a[i]-a[j])/(i-j+K)=ans
变形得(a[i]-i*ans)-(a[j]-j*ans)=k*ans
所以我们二分一下ans,有满足左边大于右边的,ans就可以更大
左边最大值可以用单调队列做
记A[i]=a[i]-ans*i
如果后面加进来的A[i]比队尾要小,队尾就没有意义了,可以删去
对于区间长度是[L,R]的限制,初始时保持距离为L,加入队列时从队头删去距离超过R-1的点即可
反过来类似,注意一些细节
另外就是区间长为L时
类似地,(a[i]-a[j])/(L-1+K)=ans
变形得:a[i]-a[j]=ans*(L-1+K)
也是二分,单调队列维护即可
复杂度O(nlogmaxans)
T3:字符串神题?
突然发现字符串长<=10.....
拿个可持久化trie维护一下就好了
儿子节点从父亲节点继承trie,再把边上的字符串插入进去即可
每次用ans[x]+ans[y]-2*ans[lca]即可
R3D1
T1:一开始想到了一个玄学做法,好像很复杂的样子...然后就安心打暴力去了
后来证了一下发现是对了,加个bitset好像可以卡过
我们对于每个点求出它能到哪些点,记为g[i][maxn],这个可以压位做到m*n/32
然后对于每个点v,处理哪些连向它的边可删
如果一个它的前驱x能够到它的另一个前驱y
那么显然x连向它的边可以删去了
然后证明没有其他可删的边
假设有一个边可删,且不满足上面的条件
那么说明x到v有其他路径
那么这条路经一定要经过v的另一个前驱z,那么x可以到z,不符假设
所以不存在这样的边
具体实现就对每个点求一个bitset,表示是否是x的前驱
在把它和每个前驱的g[i]and一下,如果有1,就说明可以从其他点过来,然后就可以删掉这条边
然后发现有点卡常,怕70分都没了,于是只开到1000,70保平安...
然后发现标程压64位.....
T2:神奇的插头DP
妈呀200*200....
一定有特殊的DP方法
D了半天不知所措....
突然发现这是很简单的网络流,每栋房子是一个点,源向它连卖给A的权值,它向汇连卖给B的的权值,相邻的点连建围墙的权值,求出最小割,拿总收益减去就是了...
然后就是15分钟写网络流系列...
然后就爆零被教做人了...
T3:这个真是字符串神题,看了标程好像是后缀数组,暴力还挂了,不知所措...
得分情况:100+0+100+70+0+0
有些题目就是要敢于去想,要相信能写出来
但是有时写暴力求稳也是很重要的...
R2D1
T1:
<span style="font-size:14px;">#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> typedef long long ll; const ll mod=(ll)1e9+7; using namespace std; int n,k; ll qpow(int a,ll b){ ll res=1,j=a; while (b){ if (b&1) res=res*j%mod; j=j*j%mod,b>>=1; } return res; } int main(){ scanf("%d%d",&n,&k); printf("%lld ",qpow(2,1ll*n*k)); return 0; }</span>
T2:
<span style="font-size:14px;">#include<cstdio> #include<cstring> #include<cassert> #include<iostream> #include<algorithm> const double eps=1e-6; const int maxn=100010; using namespace std; int cas,a[maxn],n,K,L,R; struct Tque{ int pos[maxn],head,tail;double val[maxn]; void clear(){head=1,tail=0;} void pushmin(int p,double v){ //maximize a[i]-miu*i-a[j]+miu*j //if A[j]<=A[q[tail]] //because j>q[tail] //j is better than q[tail] while (head<=tail&&v<=val[tail]) tail--; val[++tail]=v,pos[tail]=p; } void pushmax(int p,double v){ while (head<=tail&&v>=val[tail]) tail--; val[++tail]=v,pos[tail]=p; } void pop1(int p){while (head<=tail&&p-pos[head]+1>R) ++head;assert(p-pos[head]+1<=R);} void pop2(int p){while (head<=tail&&pos[head]<p-L+1) ++head;assert(pos[head]>=p-L+1);} double top(){return val[head];} }q; bool check(double miu){ q.clear(); for (int i=L;i<=n;i++){ int j=i-L+1; q.pushmin(j,a[j]-j*miu),q.pop1(i); if (a[i]-miu*i-q.top()+eps>=K*miu) return 1; } q.clear(); for (int i=L;i<=n;i++){ int j=i-L+1; q.pushmax(j,a[j]+j*miu),q.pop1(i); if (q.top()-a[i]-miu*i+eps>=K*miu) return 1; } q.clear(); for (int i=1;i<=n;i++){ q.pushmin(i,a[i]),q.pop2(i); if (a[i]-q.top()+eps>=(L-1+K)*miu) return 1; } q.clear(); for (int i=1;i<=n;i++){ q.pushmax(i,a[i]),q.pop2(i); if (q.top()-a[i]+eps>=(L-1+K)*miu) return 1; } return 0; } int main(){ //freopen("gift.in","r",stdin);freopen("gift.out","w",stdout); scanf("%d",&cas); while (cas--){ scanf("%d%d%d%d",&n,&K,&L,&R); for (int i=1;i<=n;i++) scanf("%d",&a[i]); double l=0.0,r=1000.0,mid=500.0; while (r-l>eps){ if (check(mid)) l=mid; else r=mid; mid=(l+r)/2; } printf("%.4lf ",l); } return 0; } /* 1 5 1 2 4 1 2 3 4 5 */ </span>
T3:
<span style="font-size:14px;">#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> const int maxn=100010,maxm=200010,maxt=1200010; using namespace std; int n,Q,pre[maxm],now[maxn],son[maxm],val[maxm][15],tot,pp[15],fa[maxn][22],dep[maxn];char tmp[15]; struct Trie{ int root[maxn],ch[maxt][28],tot,cnt[maxt]; void insert(int now,int pre,int s[]){ int len=0; while (s[len+1]) len++; //for (int i=1;i<=len;i++) printf("%d ",s[i]);puts("s[i]"); for (int i=1;i<=len;i++){ for (int j=1;j<=26;j++){ if (j==s[i]) ch[now][j]=++tot,cnt[tot]=cnt[ch[pre][j]]+1; else ch[now][j]=ch[pre][j]; } now=ch[now][s[i]],pre=ch[pre][s[i]]; } for (int j=1;j<=26;j++) ch[now][j]=ch[pre][j]; } int query(int now,int s[]){ for (int i=1;s[i];i++) now=ch[now][s[i]];//,printf("now=%d s[i]=%d cnt=%d ",now,s[i],cnt[now]) //puts(" "); return cnt[now]; } }T; void add(int a,int b){ pre[++tot]=now[a],now[a]=tot,son[tot]=b; for (int i=1;pp[i];i++) val[tot][i]=pp[i]; } void dfs(int x){ for (int i=1;i<=19;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for (int y=now[x];y;y=pre[y]) if (son[y]!=fa[x][0]){ T.root[son[y]]=++T.tot,T.insert(T.root[son[y]],T.root[x],val[y]); dep[son[y]]=dep[x]+1,fa[son[y]][0]=x,dfs(son[y]); } } int lca(int a,int b){ if (dep[a]<dep[b]) swap(a,b); for (int h=dep[a]-dep[b],i=18;h;i--) if (h&(1<<i)) h-=(1<<i),a=fa[a][i]; if (a==b) return a; for (int i=18;i>=0;i--) if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i]; return fa[a][0]; } void change(){ int len=strlen(tmp+1); memset(pp,0,sizeof(pp)); for (int i=1;i<=len;i++) pp[i]=tmp[i]-'a'+1; } int main(){ freopen("strings.in","r",stdin);freopen("strings.out","w",stdout); scanf("%d",&n); for (int i=1,x,y;i<n;i++){ scanf("%d%d%s",&x,&y,tmp+1); change(),add(x,y),add(y,x); } T.root[1]=++T.tot,dfs(1); scanf("%d",&Q); for (int i=1,x,y;i<=Q;i++){ scanf("%d%d%s",&x,&y,tmp+1); int u=lca(x,y);change(); //printf("x=%d y=%d lca=%d ",x,y,u); printf("%d ",T.query(T.root[x],pp)+T.query(T.root[y],pp)-2*T.query(T.root[u],pp)); /*printf("x=%d ",T.query(T.root[x],pp)); printf("y=%d ",T.query(T.root[y],pp)); printf("lca=%d ",T.query(T.root[u],pp));*/ } return 0; }</span>
R3D1
T1:这个程序只能过70分,但是是标算,还要特殊的卡常数技巧(标程是压64位,可能在64位机上要快一些就过了)
#include<cstdio> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> const int maxn1=18,maxn=30010,maxm=100010; using namespace std; struct Edge{int x,y;}E[maxm]; bitset<maxn> map[maxn]; int n,m,ans,pw[maxn1],ord[maxn];bool g[maxn1][maxn1],con[maxn1][maxn1],tmp[maxn1][maxn1],bo[maxn1]; struct Twork1{ void dfs(int x){ bo[x]=1; for (int i=1;i<=n;i++) if (g[x][i]&&!bo[i]) dfs(i); } bool check(int s){ memset(g,0,sizeof(g)),memset(tmp,0,sizeof(tmp)); for (int i=0;i<m;i++) if (pw[i]&s) g[E[i].x][E[i].y]=1; for (int i=1;i<=n;i++){ memset(bo,0,sizeof(bo)),dfs(i); for (int j=1;j<=n;j++) if (bo[j]) tmp[i][j]=1; } for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (tmp[i][j]!=con[i][j]) return 0; return 1; } void work(){ for (int i=0;i<m;i++) scanf("%d%d",&E[i].x,&E[i].y),g[E[i].x][E[i].y]=1; for (int i=1;i<=n;i++){ memset(bo,0,sizeof(bo)),dfs(i); for (int j=1;j<=n;j++) if (bo[j]) con[i][j]=1; } for (int s=0;s<pw[m];s++){ int cnt=0; for (int i=0;i<m;i++) if (s&pw[i]) cnt++; cnt=m-cnt; //printf("%d %d ",s,cnt); if (check(s)) ans=max(cnt,ans); } printf("%d ",ans); } }T1; struct Twork2{ int pre[maxm],now[maxn],son[maxm],tot,in[maxn],q[maxn],head,tail; void add(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b,in[b]++;} void top1(){ head=0,tail=0; for (int i=1;i<=n;i++) map[i][i]=1; for (int i=1;i<=n;i++) if (!in[i]) q[++tail]=i; while (head!=tail){ int x=q[++head]; for (int y=now[x];y;y=pre[y]){ if (!(--in[son[y]])) q[++tail]=son[y]; map[son[y]]|=map[x]; } } for (int i=1;i<=n;i++) map[i][i]=0; } void work(){ for (int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),add(y,x); top1(); bitset<maxn> tmp; int ans=0; for (int x=1;x<=n;x++){ tmp.reset(); for (int y=now[x];y;y=pre[y]) tmp[son[y]]=1; for (int y=now[x];y;y=pre[y]) if ((tmp&map[son[y]]).any()) ans++; } printf("%d ",ans); } }T2; int main(){ freopen("graph.in","r",stdin);freopen("graph.out","w",stdout); pw[0]=1;for (int i=1;i<=16;i++) pw[i]=pw[i-1]<<1; scanf("%d%d",&n,&m); if (n<=15&&m<=15) T1.work(); else T2.work(); return 0; } /* 5 6 1 2 2 3 3 5 4 5 1 5 1 3 7 8 1 2 2 5 5 7 1 3 6 7 1 4 4 7 3 5 */
T2:
#include<cstdio> #include<cassert> #include<cstring> #include<iostream> #include<algorithm> #define aabs(a) (a>0?a:-(a)) const int maxn=500010,maxm=1000010,inf=(int)1e9; using namespace std; int n,m,ans,pre[maxm],now[maxn],son[maxm],val[maxm],tot,dis[maxn],head,tail,q[maxm+10]; int id(int x,int y){return (x-1)*m+y;} struct Flow{ int S,T; void add(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} void ins(int a,int b,int c){add(a,b,c),add(b,a,0);assert(tot<maxn);} void clear(){memset(now,0,sizeof(now)),tot=1,S=0,T=maxn-1;} bool bfs(){ memset(dis,-1,sizeof(dis)); q[tail=1]=S,dis[S]=head=0; while (head!=tail){ if (++head>maxn) head=1; int x=q[head]; for (int y=now[x];y;y=pre[y]) if (val[y]&&dis[son[y]]==-1){ if (++tail>maxn) tail=1; dis[son[y]]=dis[x]+1,q[tail]=son[y]; } } return dis[T]>0; } int find(int x,int low){ if (x==T) return low; int y,res=0; for (y=now[x];y;y=pre[y]){ if (dis[son[y]]!=dis[x]+1||!val[y]) continue; int tmp=find(son[y],min(low,val[y])); res+=tmp,low-=tmp,val[y]-=tmp,val[y^1]+=tmp; if (!low) break; } if (!y) dis[x]=-1; return res; } void work(){ int res=0; while (bfs()) res+=find(S,inf); printf("%d ",ans-res); } }F; void init(){ scanf("%d%d",&n,&m),F.clear(); for (int i=1;i<=n;i++) for (int j=1,v;j<=m;j++){ scanf("%d",&v),ans+=aabs(v); if (v>=0) F.ins(F.S,id(i,j),v); else F.ins(id(i,j),F.T,-v); } for (int i=1;i<n;i++) for (int j=1,v;j<=m;j++) scanf("%d",&v),F.ins(id(i,j),id(i+1,j),v),F.ins(id(i+1,j),id(i,j),v); for (int i=1;i<=n;i++) for (int j=1,v;j<m;j++) scanf("%d",&v),F.ins(id(i,j),id(i,j+1),v),F.ins(id(i,j+1),id(i,j),v); } int main(){ init(),F.work(); return 0; } /* 5 5 -3 7 0 0 0 8 0 7 -10 0 0 7 0 1 0 0 0 0 0 0 -8 0 0 2 10 4 50 50 1 50 50 50 1 9 50 50 50 1 1 50 2 50 50 50 50 2 50 50 50 50 50 1 1 50 1 8 1 50 50 50 50 1 50 50 50 */
T3:不知所措....