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; }