A:node
/* 画图研究可得大部分状况都是走一个矩形 可是要考虑特殊状况 1 只有下方有点 1.1 点在s一侧:找距离s最近的,且能包含全部点的特殊点 1.2 点在s两侧:找距离最小的能把全部的点包起来的两个特殊点 2 两侧都有点(只有上方有点和这个状况同样) 2.1 点在s一侧:找最小的能把距离s远的那一侧全包围且能把距离s近的这一侧的上面包围的矩形 2.2 点在s两侧:找一个最小的四个点是特殊点的矩形 */ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define maxn 110 using namespace std; int n,r,m,k,s,mxa,mxb,mia,mib,p[maxn],ans,A,B; int main(){ scanf("%d%d%d%d%d",&n,&r,&m,&k,&s); int x,y;mia=mib=1e7; for(int i=1;i<=r;i++){ scanf("%d%d",&x,&y); if(x<s)A=1;if(x>s)B=1; if(y)mxb=max(mxb,x),mib=min(mib,x); else mxa=max(mxa,x),mia=min(mia,x); } for(int i=1;i<=m;i++)scanf("%d",&p[i]); p[++m]=1;p[++m]=n;sort(p+1,p+1+m); if(A+B==0){ printf("0\n");return 0; } if(A+B!=2){ if(mxb==0){ if(A){ for(int i=m;i>=1;i--) if(p[i]<=mia){ ans=(s-p[i])*2;break; } printf("%d\n",ans); } else { for(int i=1;i<=m;i++) if(p[i]>=mxa){ ans=(p[i]-s)*2;break; } printf("%d\n",ans); } } else { if(A){ for(int i=1;i<=m;i++) if(p[i]>=mxb){ if(s>p[i])ans+=(s-p[i])*2; ans-=(n-p[i])*2;break; } for(int i=m;i>=1;i--) if(p[i]<=mia&&p[i]<=mib){ ans-=(p[i]-1)*2;break; } ans+=k*2+(n-1)*2;printf("%d\n",ans); } else{ for(int i=1;i<=m;i++) if(p[i]>=mxa&&p[i]>=mxb){ ans-=(n-p[i])*2;break; } for(int i=m;i>=1;i--) if(p[i]<=mib){ if(s<p[i])ans+=(p[i]-s)*2; ans-=(p[i]-1)*2;break; } ans+=k*2+(n-1)*2;printf("%d\n",ans); } } return 0; } for(int i=1;i<=m;i++) if(p[i]>=mxa&&p[i]>=mxb){ ans-=(n-p[i])*2;break; } for(int i=m;i>=1;i--) if(p[i]<=mia&&p[i]<=mib){ ans-=(p[i]-1)*2;break; } if(mxb)ans+=k*2;ans+=(n-1)*2; printf("%d\n",ans);return 0; }
B:ios
/* 这题一开始思路被带到了bfs上 状态是f[x][y][t][c]第t秒到了(x,y)有了c个糖果 而后走 考虑复杂度c为1018,t最多1018*10 10*10*1018*10*1018 有点凉 考虑到不少走法是很傻逼的 须要有决策 那就把状态直接拿到dp上 去掉第四维,f[x][y][t]为最多的糖果数 t决定更新的前后 而后能够滚一下数组 至于div1 1e18的作法 好像是有循环节来着 */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 11 using namespace std; int n,m,C,sx,sy,ex,ey,a[maxn][maxn][2],T[maxn][maxn]; int main(){ scanf("%d%d%d",&n,&m,&C); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&T[i][j]); scanf("%d%d%d%d",&sx,&sy,&ex,&ey); memset(a,-127/3,sizeof(a)); a[sx][sy][0]=0; for(int k=1;;k++){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(k%T[i][j]==0){ a[i][j][k%2]=a[i][j][(k+1)%2]+1; if(i-1>=1)a[i][j][k%2]=max(a[i][j][k%2],a[i-1][j][(k+1)%2]+1); if(j-1>=1)a[i][j][k%2]=max(a[i][j][k%2],a[i][j-1][(k+1)%2]+1); if(i+1<=n)a[i][j][k%2]=max(a[i][j][k%2],a[i+1][j][(k+1)%2]+1); if(j+1<=m)a[i][j][k%2]=max(a[i][j][k%2],a[i][j+1][(k+1)%2]+1); } else { a[i][j][k%2]=a[i][j][(k+1)%2]; if(i-1>=1)a[i][j][k%2]=max(a[i][j][k%2],a[i-1][j][(k+1)%2]); if(j-1>=1)a[i][j][k%2]=max(a[i][j][k%2],a[i][j-1][(k+1)%2]); if(i+1<=n)a[i][j][k%2]=max(a[i][j][k%2],a[i+1][j][(k+1)%2]); if(j+1<=m)a[i][j][k%2]=max(a[i][j][k%2],a[i][j+1][(k+1)%2]); } } if(a[ex][ey][k%2]>=C){ printf("%d\n",k);break; } } return 0; }
E:数组
/* f[i][0/1]表示i为根的子树 且i选没选的max */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 1010 using namespace std; int n,f[maxn],d[maxn],num,head[maxn],dp[maxn][2],fa[maxn]; struct node{ int v,pre; }e[maxn*2]; void Add(int from,int to){ num++;e[num].v=to; e[num].pre=head[from]; head[from]=num; } int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); } void Dfs(int now,int from){ dp[now][0]=0;dp[now][1]=f[now]; for(int i=head[now];i;i=e[i].pre){ int v=e[i].v;if(v==from)continue; Dfs(v,now);dp[now][0]+=max(dp[v][0],dp[v][1]); dp[now][1]+=max(dp[v][0],dp[v][1]-d[min(now,v)]); } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&f[i]); for(int i=1;i<=n;i++)scanf("%d",&d[i]); for(int i=1;i<=n;i++)fa[i]=i; for(int i=2;i<=n;i++){ if(i%2==1){ if(i*3+1>n)continue; Add(i,i*3+1);Add(i*3+1,i); fa[find(i)]=find(i*3+1); } else { Add(i,i/2);Add(i/2,i); fa[find(i)]=find(i/2); } } for(int i=1;i<=n;i++) if(find(i)==i)Add(0,i); Dfs(0,-1);printf("%d\n",max(dp[0][0],dp[0][1])); return 0; }
F:优化
/* 回家好颓啊,不行啊赶忙发发博客监督本身 day1 F 关键 上升体力-- 降低体力++ 这样子的话,若是初始体力为x 则任何海拔不超过x的山都能到 若是整张图没有海拔>x的山 由于降低山须要的花费是l*l 那么显然不降最优 即裸地最短路 如今考虑很差的山v 从u->v的新的花费就是dis[u][v]+(h[v]-x)^2 因为上面的证实,就是-x不是-h[u] 另外出题人说没卡spfa是由于他那个年代不卡 也就是说如今写比较危险 而我比较喜欢写spfa 因此之后仍是写dij吧 还有别忘了longlong.... */ #include<cstdio> #include<cstring> #include<iostream> #include<queue> #define maxn 200010 #define ll long long using namespace std; ll n,m,K,num,head[maxn],h[maxn],dis[maxn],f[maxn]; struct node{ ll v,t,pre; }e[maxn*2];queue<ll>q; void Add(ll from,ll to,ll dis){ num++;e[num].t=dis; e[num].v=to; e[num].pre=head[from]; head[from]=num; } void SPFA(){ memset(dis,127/3,sizeof(dis)); dis[1]=0;ll lim=h[1]+K; q.push(1);f[1]=1;while(!q.empty()){ ll k=q.front();q.pop();f[k]=0; for(ll i=head[k];i;i=e[i].pre){ ll v=e[i].v,r=0; if(h[v]>lim)r=(h[v]-lim)*(h[v]-lim); if(dis[v]>dis[k]+e[i].t+r){ dis[v]=dis[k]+e[i].t+r; if(f[v]==0){ f[v]=1;q.push(v); } } } } } int main(){ scanf("%lld%lld%lld",&n,&m,&K); for(ll i=1;i<=n;i++) scanf("%lld",&h[i]); ll u,v,t; for(ll i=1;i<=m;i++){ scanf("%lld%lld%lld",&u,&v,&t); Add(u,v,t);Add(v,u,t); } SPFA();printf("%lld\n",dis[n]); return 0; }
G:spa
/* 首先答案矩阵包含的范围要么很大要么很小 很大的状况特判一下: 1.能包含全部:一个小矩形的全部数gcd>1 2.横着贯穿:枚举上下界 3.竖着贯穿:枚举左右界 小的状况就是在2*2的四个矩阵里找 枚举上下边界 转化成一维的问题 rmq预处理 区间gcd 而后尺取 n*n*n*logn */ #include<cstdio> #include<cstring> #include<iostream> #include<cstdlib> #include<ctime> #define maxn 210 #define ll long long using namespace std; int n,m,g[maxn][maxn],mx,a[maxn],f[maxn][20],p[maxn]; int A[maxn][maxn][20],B[maxn][maxn][20];ll ans,x,y; int gcd(int x,int y){ if(y==0)return x; return x==0?y:gcd(y,x%y); } int pre(){ for(int i=0;i<=10;i++) if((1<<i)<=200)p[1<<i]=i; for(int i=1;i<=200;i++) if(!p[i])p[i]=p[i-1]; for(int i=1;i<=n*2;i++){ for(int j=1;j<=m*2;j++)A[i][j][0]=g[i][j]; for(int k=1;k<=10;k++) for(int j=1;j+(1<<k-1)<=m*2;j++) A[i][j][k]=gcd(A[i][j][k-1],A[i][j+(1<<k-1)][k-1]); } for(int j=1;j<=m*2;j++){ for(int i=1;i<=n*2;i++)B[i][j][0]=g[i][j]; for(int k=1;k<=10;k++) for(int i=1;i+(1<<k-1)<=n*2;i++) B[i][j][k]=gcd(B[i][j][k-1],B[i+(1<<k-1)][j][k-1]); } } int Query(int l,int r){ if(l>r)return 0;int k=p[r-l+1]; return gcd(f[l][k],f[r-(1<<k)+1][k]); } int Query1(int l,int r,int t){ if(l>r)return 0;int k=p[r-l+1]; return gcd(B[l][t][k],B[r-(1<<k)+1][t][k]); } int Query2(int l,int r,int t){ if(l>r)return 0;int k=p[r-l+1]; return gcd(A[t][l][k],A[t][r-(1<<k)+1][k]); } ll Solve(int up,int down){ int N=m*2; for(int j=1;j<=N;j++) a[j]=Query1(up,down,j); for(int i=1;i<=N;i++)f[i][0]=a[i]; for(int j=1;j<=10;j++) for(int i=1;i+(1<<j-1)<=N;i++) f[i][j]=gcd(f[i][j-1],f[i+(1<<j-1)][j-1]); int l=1,r=1,now=a[1],ans=0; for(;l<=N&&r<=N;l++){ if(l>r)r=l; while(now=gcd(now,a[r])>1&&r<=N)r++; ans=max(ans,r-l); now=Query(l+1,r); } return ans*(down-up+1); } int Solve1(int up,int down){ int N=m*2; for(int j=1;j<=N;j++) a[j]=Query1(up,down,j); for(int i=1;i<=N;i++)f[i][0]=a[i]; for(int j=1;j<=10;j++) for(int i=1;i+(1<<j-1)<=N;i++) f[i][j]=gcd(f[i][j-1],f[i+(1<<j-1)][j-1]); int l=1,r=1,now=a[1],ans=0; for(;l<=N&&r<=N;l++){ if(l>r)r=l; while(now=gcd(now,a[r])>1&&r<=N)r++; ans=max(ans,r-l); now=Query(l+1,r); } return ans; } int Solve2(int lef,int rig){ int N=n*2; for(int i=1;i<=N;i++) a[i]=Query2(lef,rig,i); for(int i=1;i<=N;i++)f[i][0]=a[i]; for(int j=1;j<=10;j++) for(int i=1;i+(1<<j-1)<=N;i++) f[i][j]=gcd(f[i][j-1],f[i+(1<<j-1)][j-1]); int l=1,r=1,now=a[1],ans=0; for(;l<=N&&r<=N;l++){ if(l>r)r=l; while(now=gcd(now,a[r])>1&&r<=N)r++; ans=max(ans,r-l); now=Query(l+1,r); } return ans; } int main(){ //srand(time(0)); scanf("%d%d%lld%lld",&n,&m,&x,&y); //n=100;m=100;x=1000;y=1000; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) //g[i][j]=rand()%100000; scanf("%d",&g[i][j]); int now=0,mx; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) now=gcd(now,g[i][j]); if(now>1){ printf("%lld\n",n*m*x*y);return 0; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) g[i+n][j]=g[i][j+m]=g[i+n][j+m]=g[i][j]; pre(); mx=0;for(int i=1;i<=n*2;i++) for(int j=i;j<=n*2;j++) if(j-i+1>mx&&Solve1(i,j)==m*2) mx=max(mx,j-i+1); ans=max(ans,mx*m*y); //printf("%d\n",clock()); mx=0;for(int i=1;i<=m*2;i++) for(int j=i;j<=m*2;j++) if(j-i+1>mx&&Solve2(i,j)==n*2) mx=max(mx,j-i+1); ans=max(ans,mx*n*x); //printf("%d\n",clock()); for(int i=1;i<=n*2;i++) for(int j=i;j<=n*2;j++) ans=max(Solve(i,j),ans); //printf("%d\n",clock()); printf("%lld\n",ans); return 0; }
I:code
/* 简单的dp f[i][j][k]表示以第i个为结尾 上一个选的是p[j] k==0表示i为子序列的偶数位 1为奇数位 转移就是 枚举上次在哪里选的 而后前缀后缀和优化一下 */ #include<cstdio> #include<cstring> #include<iostream> #define maxn 2010 #define mod 1000000007 #define ll long long using namespace std; ll n,p[maxn],f[maxn][maxn][2],s[maxn][maxn][2],t[maxn][maxn][2],ans; int main(){ scanf("%lld",&n); for(ll i=1;i<=n;i++)scanf("%lld",&p[i]); for(ll i=1;i<=n;i++) for(ll j=1;j<i;j++) if(p[j]>p[i])f[i][p[j]][0]++; for(ll i=1;i<=n;i++){ for(ll j=1;j<=n;j++) s[i][j][0]=s[i][j-1][0]+f[i][j][0]; for(ll j=n;j>=1;j--) t[i][j][0]=t[i][j+1][0]+f[i][j][0]; } for(ll i=1;i<=n;i++){ for(ll j=1;j<i;j++){ if(p[i]>p[j]){ f[i][p[j]][1]+=t[j][p[i]+1][0];f[i][p[j]][1]%=mod; } if(p[j]>p[i]){ f[i][p[j]][0]+=s[j][p[j]-1][1];f[i][p[j]][0]%=mod; } } for(ll j=1;j<=n;j++){ s[i][j][0]=s[i][j-1][0]+f[i][j][0];s[i][j][0]%=mod; s[i][j][1]=s[i][j-1][1]+f[i][j][1];s[i][j][1]%=mod; } for(ll j=n;j>=1;j--){ t[i][j][0]=t[i][j+1][0]+f[i][j][0];t[i][j][0]%=mod; t[i][j][1]=t[i][j+1][1]+f[i][j][1];t[i][j][1]%=mod; } } for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++){ ans+=f[i][j][1];ans%=mod; } printf("%lld\n",ans);return 0; }