[3.3校内训练赛]
Posted FallDream
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[3.3校内训练赛]相关的知识,希望对你有一定的参考价值。
我好菜啊都不会 hzwer又出丧题啦
---------------
A.[百练2812] 恼人的青蛙
给丁一张r*c的图,上面有最多n个青蛙脚印,一个青蛙行走的路线是一条直线,且间隔距离相同,最少行走3个点。
求可能的青蛙走过的踩过最多脚印的路线的脚印数量。
r,c,n<=5000
做法:枚举两个点,check一下。
加一些剪枝,比如如果目前这条直线即使可行也不会比答案优秀,我们就可以退出了。
还可以把点按照横坐标排序,每次如果因为横坐标相差过大导致出现剪枝1的情况,就可以不搜前面这个点了,因为后面的点相差显然更大。
然后加了跑的飞快 165ms 就过了 复杂度O(能过)
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; inline int read() { int x=0,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();} return x*f; } inline int abs(int x){return x<0?-x:x;} bool yes; bool b[5005][5005]; int r,c; int n,u,v,ans=0,num,xx,yy; struct node{ int x,y; }s[5005]; bool cmp(node x,node y){return x.x<y.x;} int main() { r=read();c=read();n=read(); for(register int i=1;i<=n;i++) { s[i].x=read();s[i].y=read(); b[s[i].x][s[i].y]=1; } sort(s+1,s+n+1,cmp); for(register int i=1;i<=n;i++) for(register int j=i+1;j<=n;j++) if(abs(s[i].x-s[j].x)*ans<=r) { if(abs(s[i].y-s[j].y)*ans>c)continue; num=0;yes=true; for(xx=s[i].x,yy=s[i].y;xx>0&&yy>0&&xx<=r&&yy<=c;xx+=s[i].x-s[j].x,yy+=s[i].y-s[j].y) if(!b[xx][yy]){yes=false;break;}else ++num; if(yes)for(xx=s[j].x,yy=s[j].y;xx>0&&yy>0&&xx<=r&&yy<=c;xx+=s[j].x-s[i].x,yy+=s[j].y-s[i].y) if(!b[xx][yy]){yes=false;break;}else ++num; if(yes) ans=max(ans,num); } else break; printf("%d\\n",ans>2?ans:0); return 0; }
C.[hdu2197]本原串
求长度为n的没有循环节的二进制串的个数。n<=10^8
题解:筛出所有因数,然后容斥原理
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #define mod 2008 using namespace std; int s[10005],num[10005],n,cnt; int ans=0; int pow(int x,int p) { int sum=1; for(int i=x;p;p>>=1,i=(i*i)%mod)if(p&1) sum=(sum*i)%mod; return sum; } int main() { while(scanf("%d",&n)!=EOF) { cnt=0;ans=pow(2,n); for(int i=1;i<=sqrt(n);i++) if(n%i==0) { s[++cnt]=i;num[cnt]=-1; if(i*i!=n)s[++cnt]=n/i,num[cnt]=-1; } sort(s+1,s+cnt+1); for(int i=cnt-1;i;i--) for(int j=1;j<i;j++) if(s[i]%s[j]==0) num[j]-=num[i]; for(int i=1;i<cnt;i++)ans=(ans+1000*mod+num[i]*pow(2,s[i]))%mod; cout<<ans<<endl; } return 0; }
D.Poj2112
有c个奶牛,n个点,每个点最多m头牛,每头牛要去一个点,给丁所有牛和点的距离,求所有牛都有点去的时候最大距离的最小值
c<=200,n<=30,m<=15
二分答案,然后网络流check一下
因为是临时换题了,所以不知道还有这道大水题...没去切.....但是看看就会做(原来的D题貌似是dancing link)
E.有n个人,m个限制条件,每个限制条件要求ai比bi更前。n<=200000,m<=400000
你要在限制的基础上,安排一个顺序,让1的位置尽量小,然后2的位置尽量小........
题解:倒着建图,堆+括扑排序,倒着输出
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #define ll long long using namespace std; inline int read() { int x=0,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();} return x*f; } priority_queue<int> q; int n,m,cnt=0; struct edge{ int to,next; }e[400005]; int head[200005]; int to[200005]; int ans[200005]; void ins(int f,int t) { e[++cnt].next=head[f];head[f]=cnt; e[cnt].to=t; } int main() { n=read();m=read(); for(int i=1;i<=m;i++) { int u=read(),v=read(); ins(v,u);to[u]++; } for(int i=1;i<=n;i++)if(!to[i])q.push(i); for(int i=1;i<=n;i++) { int x=q.top();q.pop(); ans[i]=x; for(int i=head[x];i;i=e[i].next){--to[e[i].to];if(!to[e[i].to])q.push(e[i].to);} } for(int i=n;i;i--)printf("%d ",ans[i]); return 0; }
G.[bzoj3998]弦图
给定一个长度为n的字符串,求它的第k大子串(给定T,如果T=1那么不同位置相同子串可重复计算,T=0则不行) n<=500000,k<=10^9
题解:后缀自动机模板题....
去黄学长博客逛了逛发现原来可以直接用计数排序来求括扑序....
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int c[1000005][26],step[1000005],fail[1000005]; long long val[1000005],sum[1000005]; int v[500005],rk[1000005]; char s[500005]; int cnt=1,last=1,T,k,n; void ins(int x) { int p=last,np=++cnt;step[np]=step[last]+1;val[np]=1; for(;p&&!c[p][x];p=fail[p])c[p][x]=np; if(!p)fail[np]=1; else { int q=c[p][x]; if(step[q]==step[p]+1) fail[np]=q; else { int nq=++cnt;step[nq]=step[p]+1; for(int i=0;i<26;i++)c[nq][i]=c[q][i]; fail[nq]=fail[q];fail[q]=fail[np]=nq; for(;c[p][x]==q;p=fail[p])c[p][x]=nq; } } last=np; } void work() { for(int i=1;i<=cnt;i++)v[step[i]]++; for(int i=1;i<=n;i++)v[i]+=v[i-1]; for(int i=cnt;i;i--) rk[v[step[i]]--]=i; if(T==1)for(int i=cnt;i;i--) val[fail[rk[i]]]+=val[rk[i]]; else for(int i=cnt;i;i--) val[rk[i]]=1; val[1]=0; for(int i=cnt;i;i--) { sum[rk[i]]=val[rk[i]]; for(int j=0;j<26;j++)sum[rk[i]]+=sum[c[rk[i]][j]]; } } void dfs(int x,int k) { if(k<=val[x])return; k-=val[x]; for(int j=0;j<26;j++) if(int t=c[x][j]) { if(sum[t]>=k) {putchar(j+\'a\');dfs(t,k);return;} else k-=sum[t]; } } int main() { scanf("%s",s+1);n=strlen(s+1); for(int i=1;s[i];ins(s[i++]-\'a\')); scanf("%d%d",&T,&k); work(); if(sum[1]<k)puts("-1"); else dfs(1,k); return 0; }
以上是关于[3.3校内训练赛]的主要内容,如果未能解决你的问题,请参考以下文章