【noip】跟着洛谷刷noip题2
noip好难呀。
上一个感觉有点长了,重开一个。
36.Vigenère 密码
粘个Openjudge上的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include <cstdlib> #include <algorithm> #include <iomanip> using namespace std; char a[101],s[1001],b[1001]; int c[1001],j; int main() { int la,ls,i,j; gets (a); gets (s); la= strlen (a); ls= strlen (s); for (i=0;i<la;i++) { if (a[i]<=90) a[i]=a[i]+32;} for (i=0;i<la;i++) c[i]=a[i]-97; for (i=0;i<ls;i++) c[i+la]=c[i]; for (i=0;i<ls;i++) { b[i]=s[i]-c[i]; if ((s[i]>=65&&b[i]<65)||(s[i]>=97&&b[i]<97)) b[i]=b[i]+26; } puts (b); return 0; } |
37.国王游戏
贪心。手动艾特LLJ。
粘一个别人的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #include<iostream> #include<algorithm> #include<cstring> using namespace std; int n,i,sum[10000],kx,ky,t[10000],ans[10000]; struct node { int x; int y; }a[1001]; //每个大臣的左右手数值 bool cmp(node a,node b) { return a.x*a.y<b.x*b.y; //按照左右手乘积排序 } bool judge() //用来判断当前大臣的结果是不是比ans大 { int i; for (i=1;i<=t[0];++i) if (t[i]>ans[i]) return true ; else if (t[i]<ans[i]) return false ; return false ; } void mul( int x) //高乘 { int g=0,i; for (i=1;i<=sum[0];++i) { sum[i]=sum[i]*x+g; g=sum[i]/10; sum[i]=sum[i]%10; } while (g!=0) { ++sum[0]; sum[sum[0]]=g%10; g/=10; } } void divv( int x) //高除,附带比较当前大臣答案和ans的大小关系 { int num=0,i=sum[0]+1,s=0; memset (t,0, sizeof (t)); while (num<x) { --i; num=num*10+sum[i]; } t[0]=i; for (;i>=1;--i) { t[++s]=num/x; num=num%x*10+sum[i-1]; } //高除,其中t保存当前大臣的结果 if (t[0]>ans[0]||t[0]==ans[0]&&judge()) //.若比ans大则更新ans { ans[0]=t[0]; for (i=1;i<=t[0];++i) ans[i]=t[i]; } } int main() { cin>>n; cin>>kx>>ky; sum[1]=kx; sum[0]=1; ans[0]=1; ans[1]=0; //下标0保存长度 //sum用来计算到第i个大臣的左手乘积 for (i=1;i<=n;++i) cin>>a[i].x>>a[i].y; sort(a+1,a+n+1,cmp); for (i=1;i<=n;++i) { mul(a[i].x); divv(a[i].y*a[i].x); //因a[i].x当前已经乘过所以除的时候要再除一遍 } for (i=1;i<=ans[0];++i) cout<<ans[i]; } |
38.同余方程
做不来,是不是没救了。。。
裸的扩展欧几里得。
注意扩欧先除再乘以免爆炸。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //Twenty #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<ctime> #include<queue> using namespace std; typedef long long LL; LL a,b,x,y,d; void exgcd (LL a,LL b,LL &x,LL &y,LL &d) { if (!b) {d=a; x=1; y=0; return ;} exgcd(b,a%b,y,x,d); y=y-(a/b*x); } int main() { cin>>a>>b; exgcd(a,b,x,y,d); cout<<(x+b)%b<<endl; return 0; } |
39.借教室
第一眼线段树模板,听说会被卡,卡卡常应该能过吧。
正解 二分+差分。
一开始把某个n写成m,一直WA第18个点。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | //Twenty #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<ctime> #include<queue> using namespace std; typedef long long LL; const int maxn=1e6+5; int n,m,a[maxn],b[maxn],ll[maxn],rr[maxn],c[maxn]; void read( int &x) { char ch=getchar(); int ret=0,f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; x=ret*f; } void init() { read(n); read(m); for ( int i=1;i<=n;i++) read(a[i]); for ( int i=1;i<=m;i++) { read(c[i]); read(ll[i]); read(rr[i]); } } int ok( int x) { for ( int i=1;i<=n;i++) b[i]=a[i]-a[i-1]; for ( int i=1;i<=x;i++) { int l=ll[i],r=rr[i]; b[l]-=c[i]; b[r+1]+=c[i]; } int now=0; for ( int i=1;i<=n;i++) { now+=b[i]; if (now<0) return 0; } return 1; } void work() { int l=0,r=m,ans=0; while (l<=r) { int mid=(l+r)>>1; if (!ok(mid)) ans=mid,r=mid-1; else l=mid+1; } if (!ans) printf( "0\n" ); else { printf( "-1\n" ); printf( "%d\n" ,ans); } } int main() { init(); work(); return 0; } |
40.津津的储蓄计划
Openjudge打不开啦,随便抄个别人的代码水一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <iostream> using namespace std; int main() { const int m=300; bool flag= true ; int h=0,s=0; int a; for ( int i=1;i<13;i++) { cin>>a; h+=m; if (h<a) { cout<<-i; flag= false ; break ; } int left=h-a; h=left%100; s+=left-h; } if (flag) cout<<s*1.2+h; return 0; } |
41.合并果子
优先队列水过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | //Twenty #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<ctime> #include<queue> const int maxn=10005; using namespace std; typedef long long LL; int n,x,ok[maxn],ans; void read( int &x) { char ch=getchar(); int ret=0,f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; x=ret*f; } priority_queue< int ,vector< int >,greater< int > >que; int main() { read(n); for ( int i=1;i<=n;i++) { read(x); que.push(x); } while (!que.empty()) { int a=que.top(); que.pop(); if (que.empty()) break ; int b=que.top(); que.pop(); ans+=a+b; que.push(a+b); } printf( "%d\n" ,ans); return 0; } |
31.合唱队形
抄个代码水一水
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include<iostream> #include<cmath> using namespace std; int num[1010]; //每个人的身高 int ans=1; //最后留下的人数 int sum1[1010],sum2[1010]; //升序列和降序列中留下的人数 int main(){ int n; cin>>n; for ( int i=1;i<=n;i++){ cin>>num[i]; //输入 sum1[i]=1; //留下的人数,至少为1 sum2[i]=1;} for ( int i=1;i<=n;i++) for ( int j=1;j<i;j++) if (num[i]>num[j]) //如果i位置的值大于j位置的,这是可以作为上升子序列 sum1[i]=max(sum1[i],sum1[j]+1); //比较不取i位置和取i位置哪个留下的人多 for ( int i=n;i>=1;i--) //最小降序列,反着枚举 for ( int j=n;j>i;j--) if (num[i]>num[j]) sum2[i]=max(sum2[i],sum2[j]+1); for ( int i=1;i<=n;i++) ans=max(ans,(sum2[i]+sum1[i]-1)); //ans是留下的人数,和每一种方案留下的人数比较。减一是中间的人重复计数。 cout<<n-ans<<endl; //n是总人数,ans留下的人数 return 0; } |
32.统计数字
同上,装出自己做了题的样子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <iostream> #include <algorithm>//快排头文件 using namespace std; bool cmp ( int a, int b) //养成写排序规则的好习惯 { return a<b; } int main () { int n; cin>>n; int a[n]; for ( int i=0;i<n;i++) cin>>a[i]; sort (a,a+n,cmp); //进行升序排序 int ans=1; //计数变量 for ( int i=1;i<n;i++) { if (a[i-1]==a[i]) ans++; //若两两相等,计数加一 else {cout<<a[i-1]<< ' ' <<ans<<endl;ans=1;} //不等就输出,重新赋值 } cout<<a[n-1]<< ' ' <<ans<<endl; //因为最后一个数字还未输出,所以输出 return 0; } |
33.天天爱跑步
一开始觉得超级难写,然而写起来意外的顺利而且一A了,就比较开心。
这两天碰到不少差分,才发现其实自己以前根本不知道差分到底是啥,差分真是神奇的东西。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | //Twenty #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<ctime> #include<queue> const int maxn=300000; using namespace std; typedef long long LL; int n,m,w[maxn],up[maxn<<1],dn[maxn<<1]; vector< int >vcu[maxn][2]; vector< int >vcd[maxn][2]; void read( int &x) { int ret=0,f=1; char ch=getchar(); while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; x=ret*f; } int ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1]; void add( int u, int v) { nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; } int f[maxn][20],R[maxn]; void dfs1( int x, int fa) { f[x][0]=fa; R[x]=R[fa]+1; for ( int i=fir[x];i;i=nxt[i]) if (to[i]!=fa){ dfs1(to[i],x); } } void make_st() { for ( int i=1;i<=19;i++) for ( int x=1;x<=n;x++) { f[x][i]=f[f[x][i-1]][i-1]; } } int get_lca( int x, int y, int &tp) { int fl=0; if (R[x]<R[y]) {fl=1; swap(x,y);} for ( int i=19;i>=0;i--) if (f[x][i]&&R[f[x][i]]>R[y]) x=f[x][i]; if (f[x][0]==y) {tp=x; return f[x][0];} if (f[x][0]&&R[f[x][0]]>=R[y]) x=f[x][0]; for ( int i=19;i>=0;i--) if (f[x][i]&&f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; if (fl) tp=x; else tp=y; return f[x][0]; } void init() { read(n); read(m); for ( int i=1;i<n;i++) { int u,v; read(u); read(v); add(u,v); } dfs1(1,0); make_st(); for ( int i=1;i<=n;i++) read(w[i]); for ( int i=1;i<=m;i++) { int x,y,z,tp; read(x); read(y); z=get_lca(x,y,tp); int len=R[x]-R[z]+R[y]-R[z]; vcu[x][1].push_back(R[x]); vcu[z][0].push_back(R[x]); if (y==z) continue ; vcd[y][1].push_back(maxn+len-R[y]); vcd[tp][0].push_back(maxn+len-R[y]); } } int ans[maxn]; void dfs( int x, int fa) { int nup=w[x]+R[x],nd=w[x]-R[x]+maxn; int prup=up[nup],prd=dn[nd]; for ( int i=fir[x];i;i=nxt[i]) if (to[i]!=fa) { dfs(to[i],x); } for ( int i=0;i<vcu[x][1].size();i++) { int tp=vcu[x][1][i]; up[tp]++; } for ( int i=0;i<vcd[x][1].size();i++) { int tp=vcd[x][1][i]; dn[tp]++; } ans[x]+=(up[nup]-prup); ans[x]+=(dn[nd]-prd); for ( int i=0;i<vcu[x][0].size();i++) { int tp=vcu[x][0][i]; up[tp]--; } for ( int i=0;i<vcd[x][0].size();i++) { int tp=vcd[x][0][i]; dn[tp]--; } } void work() { dfs(1,0); for ( int i=1;i<n;i++) printf( "%d " ,ans[i]); printf( "%d\n" ,ans[n]); } int main() { init(); work(); return 0; } |
34.换教室
期望dp.
dp[i][j][k]表示第i节课为止,共申请了j次,本次申请或不申请的期望。
然后就很好转移了,很好想但是写起来比较恶心,十分难看。
神奇的是数据两个教室之间会用很多条路你要取最小的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | //Twenty #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<ctime> #include<queue> const int maxv=299+5; const int maxn=2005; using namespace std; typedef long long LL; int n,m,v,e,a[maxn],b[maxn]; double c[maxn],dp[maxn][maxn][2],d[maxv][maxv]; void init() { scanf( "%d%d%d%d" ,&n,&m,&v,&e); for ( int i=1;i<=n;i++) scanf( "%d" ,&a[i]); for ( int i=1;i<=n;i++) scanf( "%d" ,&b[i]); for ( int i=1;i<=n;i++) scanf( "%lf" ,&c[i]); memset(d,127, sizeof (d)); for ( int i=1;i<=e;i++) { int x,y,z; scanf( "%d%d%d" ,&x,&y,&z); d[x][y]=min(d[x][y],( double )z); d[y][x]=d[x][y]; } } void floyd() { for ( int k=1;k<=v;k++) for ( int i=1;i<=v;i++) for ( int j=1;j<=v;j++) { if (i==j) d[i][j]=0; d[i][j]=min(d[i][j],d[i][k]+d[k][j]); } } void work() { floyd(); memset(dp,127, sizeof (dp)); dp[1][0][0]=0; dp[1][1][1]=0; for ( int i=2;i<=n;i++) { int up=min(i,m); for ( int j=0;j<=up;j++) { dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][0]+d[a[i-1]][a[i]]); if (j) { dp[i][j][0]=min(dp[i][j][0],dp[i-1][j][1]+ d[a[i-1]][a[i]]*(1-c[i-1])+d[b[i-1]][a[i]]*c[i-1]); dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][0]+ c[i]*d[a[i-1]][b[i]]+(1-c[i])*d[a[i-1]][a[i]]); } if (j>=2) dp[i][j][1]=min(dp[i][j][1],dp[i-1][j-1][1]+c[i-1]*c[i]*d[b[i-1]][b[i]] +c[i-1]*(1-c[i])*d[b[i-1]][a[i]]+(1-c[i-1])*c[i]*d[a[i-1]][b[i]] +(1-c[i-1])*(1-c[i])*d[a[i-1]][a[i]]); } } double ans=1e9; for ( int i=0;i<=m;i++) { ans=min(ans,dp[n][i][1]); ans=min(ans,dp[n][i][0]); } printf( "%.2lf\n" ,ans); } int main() { init(); work(); return 0; } |
35.双栈排序
发现两个元素i, j不能放进同一个栈当且仅当存在k使得i<j<k,a_k<a_i<a_j
将这样i,j之间连边,整个图跑一遍二分图染色。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> #include<stack> const int maxn=1005; typedef long long LL; using namespace std; int n,a[maxn],col[maxn],ok[maxn],mi[maxn],fl; void read( int &ret) { char ch=getchar(); ret=0; int f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; } void init() { read(n); for ( int i=1;i<=n;i++) read(a[i]); } int ecnt,fir[maxn],nxt[maxn*maxn],to[maxn*maxn]; void add( int u, int v) { nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; } void dfs( int x) { for ( int i=fir[x];i;i=nxt[i]) { if (col[to[i]]!=-1) { if (col[to[i]]==col[x]) fl=1; return ; } else { col[to[i]]=col[x]^1; dfs(to[i]); } } } stack< int >s1; stack< int >s2; void work() { memset(col,-1, sizeof (col)); mi[n]=a[n]; for ( int i=n-1;i>=1;i--) mi[i]=min(mi[i+1],a[i]); for ( int i=1;i<=n;i++) for ( int j=i+1;j<=n;j++) if (a[j]>a[i]&&(j+1<=n&&mi[j+1]<a[i])) add(i,j); for ( int i=1;i<=n;i++) if (col[i]==-1) { col[i]=1; dfs(i); if (fl) break ; } if (fl) { printf( "0\n" ); return ; } int now=0; for ( int i=1;i<=n;i++) { int x=s1.empty()?0:s1.top(); int y=s2.empty()?0:s2.top(); while (x==now+1) { s1.pop(); x=s1.empty()?0:s1.top(); now++; printf( "b " ); } if (col[i]==1) { s1.push(a[i]); printf( "a " ); } else { while (y==now+1) { s2.pop(); y=s2.empty()?0:s2.top(); now++; printf( "d " ); } s2.push(a[i]); printf( "c " ); } } while (!s1.empty()||!s2.empty()) { int x=s1.empty()?0:s1.top(); int y=s2.empty()?0:s2.top(); if (x==now+1) { now++; printf( "b " ); s1.pop(); } else if (y==now+1) { now++; printf( "d " ); s2.pop(); } } printf( "\n" ); } int main() { init(); work(); return 0; } |
36.组合数问题
这种水题去年的我竟然做不来?太弱啦,怪不得当时学长感觉很无语23333
n^2预处理出组合数和答案,O(1)询问即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> typedef long long LL; using namespace std; int n,m,k,t,C[2005][2005],ans[2005][2005]; void read( int &ret) { char ch=getchar(); ret=0; int f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; } void pre() { for ( int i=0;i<=2000;i++) C[i][0]=1; for ( int i=1;i<=2000;i++) { for ( int j=1;j<=2000;j++) { if (j<=i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%k; ans[i][j]=ans[i][j-1]; if (j<=i&&!C[i][j]) ans[i][j]++; } } for ( int i=1;i<=2000;i++) for ( int j=1;j<=2000;j++) ans[i][j]+=ans[i-1][j]; } void init() { read(t); read(k); pre(); for ( int i=1;i<=t;i++) { read(n); read(m); m=min(n,m); printf( "%d\n" ,ans[n][m]); } } int main() { init(); return 0; } |
37.子串
dp.比较好想,dp[i][j][k]表示当前匹配到b的第i位,已经用了j个串,当且位匹配或者不匹配的方案数。
注意,开滚动数组转移,不合法的状态要赋为0。然后上一位是匹配上的这一位继续匹配的话可以不开也可以重开一段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> typedef long long LL; using namespace std; const int maxn=1005; const int maxm=205; int n,m,kk; const int mod=1e9+7; char a[maxn],b[maxm]; LL dp[2][maxm][maxm][2]; void read( int &ret) { char ch=getchar(); ret=0; int f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; } void init() { read(n); read(m); read(kk); scanf( "%s" ,a+1); scanf( "%s" ,b+1); } void work() { int o=0; LL ans=0; dp[o][0][0][0]=1; for ( int i=1;i<=n;i++) { o^=1; int up=min(i,m); for ( int j=0;j<=m;j++) for ( int k=0;k<=j;k++) { dp[o][j][k][0]=(dp[o^1][j][k][0]+dp[o^1][j][k][1])%mod; if (a[i]==b[j]) { dp[o][j][k][1]=dp[o^1][j-1][k][1]; if (k) (dp[o][j][k][1]+=(dp[o^1][j-1][k-1][0]+dp[o^1][j-1][k-1][1])%mod)%mod; } else dp[o][j][k][1]=0; if (k==kk&&j==m) (ans+=dp[o][j][k][1])%=mod; } } printf( "%lld\n" ,ans); } int main() { init(); work(); return 0; } |
38.蚯蚓
三个队列维护。
注意要开LL,然后开了LL以后极大值要有那么大。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> #define INF 1e18 typedef long long LL; using namespace std; const int maxm=7e6+5; const int maxn=1e5+5; int n,m,q,u,v,t; LL a[maxn]; queue<LL>que[3]; void read(LL &ret) { char ch=getchar(); ret=0; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; } bool cmp( const int &A, const int &B) { return A>B; } void init() { scanf( "%d%d%d%d%d%d" ,&n,&m,&q,&u,&v,&t); for ( int i=1;i<=n;i++) read(a[i]); } LL ck( int i) { return que[i].empty()?-INF:que[i].front(); } void work() { sort(a+1,a+n+1,cmp); for ( int i=1;i<=n;i++) que[0].push(a[i]); for ( int ti=1;ti<=m;ti++) { LL a=ck(0),b=ck(1),c=ck(2); LL mx=max(max(a,b),c); if (mx==a) que[0].pop(); else if (mx==b) que[1].pop(); else que[2].pop(); mx+=(LL)(ti-1)*q; if (ti%t==0) printf( "%lld " ,mx); LL ll=(( double )u/v)*mx,rr=mx-ll; if (ll<rr) swap(ll,rr); que[1].push(ll-ti*q); que[2].push(rr-ti*q); } printf( "\n" ); int sz=0; for (;;) { LL a=ck(0),b=ck(1),c=ck(2); LL mx=max(max(a,b),c); if (mx==a) que[0].pop(); else if (mx==b) que[1].pop(); else que[2].pop(); mx+=(LL)m*q; ++sz; if (sz%t==0) printf( "%lld " ,mx); if (sz==n+m) break ; } printf( "\n" ); } int main() { init(); work(); return 0; } |
39. 解方程
对质数p取模,若数i不合法则i+p也不合法。多取几个模一模,把不合法的筛掉。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> typedef long long LL; using namespace std; const int maxn=1000005; LL n,m,a[150][5],p[5]={10007,10917,30071,12007,65537},no[maxn]; void read(LL ret[]) { char ch=getchar(); int f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) { for ( int i=0;i<5;i++) ret[i]=(ret[i]*10+ch- '0' )%p[i]; } if (f==-1) { for ( int i=0;i<5;i++) ret[i]=p[i]-ret[i]; } } void init() { scanf( "%d%d" ,&n,&m); for ( int i=1;i<=n+1;i++) read(a[i]); } int ok( int x, int o) { LL sum=0,xx=x; for ( int i=n+1;i>=1;i--) { sum=((sum+a[i][o])*xx)%p[o]; } return sum==0; } void work() { for ( int o=0;o<5;o++) { for ( int i=1;i<=p[o];i++) { if (!ok(i,o)) { for ( int j=i;j<=m;j+=p[o]) { no[j]=1; } } } } int ans=0; for ( int i=1;i<=m;i++) if (!no[i]) ans++; printf( "%d\n" ,ans); for ( int i=1;i<=m;i++) if (!no[i]) printf( "%d\n" ,i); } int main() { init(); work(); return 0; } |
40.运输计划
又一道树上差分。二分+树上差分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> const int maxn=300005; typedef long long LL; using namespace std; int n,m; void read( int &ret) { char ch=getchar(); ret=0; int f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; } int ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1]; void add( int u, int v, int w) { nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w; nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w; } int x[maxn],y[maxn],z[maxn],d[maxn]; void init() { read(n); read(m); for ( int i=1;i<n;i++) { int u,v,w; read(u); read(v); read(w); add(u,v,w); } for ( int i=1;i<=m;i++) { read(x[i]); read(y[i]); } } int R[maxn],f[maxn][20],dis[maxn]; void dfs( int x, int fa) { f[x][0]=fa; R[x]=R[fa]+1; for ( int i=fir[x];i;i=nxt[i]) if (to[i]!=fa) { dis[to[i]]=dis[x]+val[i]; dfs(to[i],x); } } void make_st() { for ( int i=1;i<=19;i++) for ( int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1]; } int get_lca( int a, int b) { if (R[a]<R[b]) swap(a,b); for ( int i=19;i>=0;i--) if (f[a][i]&&R[f[a][i]]>=R[b]) a=f[a][i]; if (a==b) return a; for ( int i=19;i>=0;i--) if (f[a][i]&&f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i]; return f[a][0]; } int g[maxn],cnt,mxx; int DFS( int x, int fa, int pr, int mid) { for ( int i=fir[x];i;i=nxt[i]) if (to[i]!=fa) { if (DFS(to[i],x,i,mid)) return 1; g[x]+=g[to[i]]; } if (g[x]==cnt&&mxx-val[pr]<=mid) return 1; return 0; } int check( int mid) { cnt=0; mxx=0; memset(g,0, sizeof (g)); for ( int i=1;i<=n;i++) { if (d[i]>mid) { cnt++; g[x[i]]++; g[y[i]]++; g[z[i]]-=2; mxx=max(mxx,d[i]); } } return DFS(1,0,0,mid); } void work() { dfs(1,0); make_st(); for ( int i=1;i<=n;i++) { z[i]=get_lca(x[i],y[i]); d[i]=dis[x[i]]+dis[y[i]]-2*dis[z[i]]; } int l=0,r=3e8,ans; while (l<=r) { int mid=(l+r)>>1; if (check(mid)) ans=mid,r=mid-1; else l=mid+1; } printf( "%d\n" ,ans); } int main() { init(); work(); return 0; } |
41.开车旅行
把高度排序连成链表,从1到n看每个人左右四个,它的最大和次大一定在其中,然后把它从链表中删掉保证现在要找的人左右都在它后面。
然后一轮开车为a跳到它的次大b再跳到它的最大,做倍增。
感觉挺好写的然后犯了一大堆智障错误,调到死亡。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> #define INF 0xfffffff const int maxn=100005; typedef long long LL; using namespace std; int n,m,h[maxn],a[maxn],zd[maxn],cd[maxn],x0,s[maxn],lim[maxn]; void read( int &ret) { char ch=getchar(); ret=0; int f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; ret*=f; } bool cmp( const int &A, const int &B) { return h[A]<h[B]; } void init() { read(n); for ( int i=1;i<=n;i++) { a[i]=i; read(h[i]); } read(x0); read(m); for ( int i=1;i<=m;i++) { read(s[i]); read(lim[i]); } } int p[maxn][20]; LL da[maxn][20],db[maxn][20]; void make_st() { for ( int i=1;i<=n;i++) { p[i][0]=zd[cd[i]]; da[i][0]=abs(h[cd[i]]-h[i]); db[i][0]=abs(h[zd[cd[i]]]-h[cd[i]]); } for ( int i=1;i<=19;i++) for ( int j=1;j<=n;j++) { p[j][i]=p[p[j][i-1]][i-1]; da[j][i]=da[j][i-1]+da[p[j][i-1]][i-1]; db[j][i]=db[j][i-1]+db[p[j][i-1]][i-1]; } } void cal( int st, int limit,LL &az,LL &bz) { int now=st; az=0; bz=0; for ( int i=19;i>=0;i--) { if (p[now][i]&&az+bz+da[now][i]+db[now][i]<=limit) { az+=da[now][i]; bz+=db[now][i]; now=p[now][i]; } } if (cd[now]&&az+bz+abs(h[cd[now]]-h[now])<=limit) az+=abs(h[cd[now]]-h[now]); } void ck( int i, int x, int &a, int &b) { if (!i) return ; if (!a) a=i; else if (!b) { b=i; if (abs(h[a]-h[x])>abs(h[b]-h[x])) swap(a,b); } else { if (abs(h[i]-h[x])<abs(h[a]-h[x])) b=a,a=i; else if (abs(h[i]-h[x])<abs(h[b]-h[x])) b=i; } } int pr[maxn],nx[maxn]; void work() { sort(a+1,a+n+1,cmp); for ( int i=1;i<=n;i++) { pr[a[i]]=a[i-1]; nx[a[i]]=a[i+1]; } for ( int i=1;i<=n;i++) { int aa=0,bb=0; ck(pr[i],i,aa,bb); ck(pr[pr[i]],i,aa,bb); ck(nx[i],i,aa,bb); ck(nx[nx[i]],i,aa,bb); if (nx[i]) pr[nx[i]]=pr[i]; if (pr[i]) nx[pr[i]]=nx[i]; zd[i]=aa; cd[i]=bb; } make_st(); int ans=0,ok=0; double now=INF; for ( int i=1;i<=n;i++) { LL a,b; cal(i,x0,a,b); if (!ok||( double )a/b<now) { ans=i; ok=1; now=( double )a/b; } } printf( "%d\n" ,ans); for ( int i=1;i<=m;i++) { LL a,b; cal(s[i],lim[i],a,b); printf( "%lld %lld\n" ,a,b); } } int main() { init(); work(); return 0; } |
42.愤怒的小鸟
其实去年考完Noip不久就写了这道题,不过当时觉得还是很难,而且几乎照着某个题解抄了一遍后来自己根本没有印象,就又写了一下。
然后发现其实蛮简单的,而且感觉去年d2比d1简单得多呀,
d1t1不说了签到题,t2,一道史无前例的神题,t3又考了期望,难得一比,相比d2t1水题,t2暴力有70~85分,t3水状压,多么亲切。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> #define eps 1e-10 typedef long long LL; using namespace std; const int maxn=20; int n,m,tot,z[500],dp[1<<19]; double x[maxn],y[maxn]; void cal( int u, int v) { if (x[u]==x[v]) return ; double b=(y[u]*x[v]*x[v]-y[v]*x[u]*x[u])/(x[u]*x[v]*x[v]-x[v]*x[u]*x[u]); double a=(y[u]-b*x[u])/(x[u]*x[u]); if (a>0) return ; z[++tot]|=(1<<u-1); z[tot]|=(1<<v-1); for ( int k=v+1;k<=n;k++) if (fabs(x[k]*x[k]*a+x[k]*b-y[k])<=eps) z[tot]|=(1<<k-1); } void work() { tot=0; memset(dp,127, sizeof (dp)); dp[0]=0; for ( int i=1;i<=n;i++) for ( int j=i+1;j<=n;j++) cal(i,j); for ( int i=1;i<=n;i++) z[++tot]=(1<<i-1); int nn=(1<<n)-1; for ( int j=0;j<=nn;j++) for ( int i=1;i<=tot;i++) if ((j|z[i])>j) dp[j|z[i]]=min(dp[j|z[i]],dp[j]+1); printf( "%d\n" ,dp[nn]); for ( int i=1;i<=tot;i++) z[i]=0; } void init() { int T; scanf( "%d" ,&T); while (T--) { scanf( "%d%d" ,&n,&m); for ( int i=1;i<=n;i++) scanf( "%lf%lf" ,&x[i],&y[i]); work(); } } int main() { init(); return 0; } |
43.疫情控制
二分+树上贪心。下次是不是该出一道二分+树上dp了。
De了超级久的Bug,然后今天洛谷还各种炸。。。
不得不说codevs真是,,直到洛谷活过来让我A了都没有测出来
题解:
贪心:若一个军队没有到根,那么它越往上走越优。
二分一个答案,每个军队倍增地往上跳,若是在答案范围内跳不到根,就把能跳到的最高点占领。
若是能跳到根还能跳,就存下来,方便别人用。
dfs一遍把已经占领的子树确定下来,然后处理没有被完全占领的子树。这些地方一定是在跟的儿子那里被占领。
贪心:询问没有被完全占领的儿子,若是它这里有一个还能跳的距离小于它到根的就直接由它来占领自己,可以用个堆维护。(记得清0)
(自己的不一定帮自己,存在自己的儿子中的军队去帮助别人再让另一个人来帮助自己的情况)
剩下的儿子到根的距离存下来,排序,和还能跳的数组排序,贪心地从最大的开始比较。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> typedef long long LL; using namespace std; const int maxn=50005; void read( int &ret) { char ch=getchar(); ret=0; int f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; ret*=f; } int ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1]; void add( int u, int v, int w) { nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w; nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w; } LL sum; int n,m, is [maxn],sz; void init() { read(n); for ( int i=1;i<n;i++) { int u,v,w; read(u); read(v); read(w); add(u,v,w); sum+=w; } read(m); for ( int i=1;i<=m;i++) { int x; read(x); is [++sz]=x; } } int f[maxn][20]; LL d[maxn][20]; void dfs( int x, int fa) { f[x][0]=fa; for ( int i=fir[x];i;i=nxt[i]) if (to[i]!=fa) { d[to[i]][0]=val[i]; dfs(to[i],x); } } void make_st() { for ( int j=1;j<=19;j++) for ( int i=1;i<=n;i++) { f[i][j]=f[f[i][j-1]][j-1]; d[i][j]=d[i][j-1]+d[f[i][j-1]][j-1]; } } int ok[maxn]; int DFS( int x, int fa) { int fl=1; for ( int i=fir[x];i;i=nxt[i]) if (to[i]!=fa) { if (ok[to[i]]) continue ; if (!DFS(to[i],x)) fl=0; else ok[to[i]]=1; } if (fl==0||!nxt[fir[x]]) return 0; return 1; } bool cmp( const int &A, const int &B) { return A>B; } priority_queue< int ,vector< int >,greater< int > >que[maxn]; int a[maxn],b[maxn],tota,totb; int check(LL mid) { if (mid==1) { int debug=1; } memset(ok,0, sizeof (ok)); memset(a,0, sizeof (a)); memset(b,0, sizeof (b)); tota=totb=0; for ( int i=fir[1];i;i=nxt[i]) { int y=to[i]; while (!que[y].empty() ) { que[y].pop(); } } for ( int i=1;i<=sz;i++) { int x= is [i]; if (x==1) a[++tota]=mid; LL now=0; for ( int j=19;j>=0;j--) if (f[x][j]&&f[x][j]!=1&&d[x][j]+now<=mid) { now+=d[x][j]; x=f[x][j]; } if (f[x][0]==1&&now+d[x][0]<mid) { que[x].push(mid-(now+d[x][0])); } else ok[x]=1; } if (ok[1]) return 1; if (DFS(1,0)) return 1; for ( int i=fir[1];i;i=nxt[i]) { int y=to[i]; if (!ok[y]) { if (!que[y].empty() ) { int z=que[y].top(); if (z<val[i]) { que[y].pop(); ok[y]=1; } else b[++totb]=val[i]; } else b[++totb]=val[i]; } while (!que[y].empty()) { int z=que[y].top(); a[++tota]=z; que[y].pop(); } } if (!totb) return 1; sort(a+1,a+tota+1,cmp); sort(b+1,b+totb+1,cmp); for ( int i=1;i<=totb;i++) if (a[i]<b[i]) return 0; return 1; } void work() { dfs(1,0); make_st(); LL l=0,r=sum,ans=-1; while (l<=r) { LL mid=(l+r)>>1; if (check(mid)) ans=mid,r=mid-1; else l=mid+1; } printf( "%lld\n" ,ans); } int main() { init(); work(); return 0; } |
44.飞扬的小鸟
debug到怀疑人生系列
背包,往下掉是01背包,往上走是完全背包。
几个坑点,dp[i-1][m]可以转移到dp[i][m](到了顶继续往上还是在顶上)
向上飞转移的时候只判断从i-1转移来的状态要合法,i转移来的状态不一定合法(连续跳多次其实是一次性跳上去的,中途的某个位置不一定合法)
先跑往上跳的再跑往下掉的(不能从掉来的位置往上跳)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<queue> #include<cmath> #include<ctime> #define INF 0xfffffff typedef long long LL; using namespace std; const int maxn=10005; int n,m,kk; int up[maxn],dn[maxn],l[maxn],h[maxn]; void read( int &ret) { char ch=getchar(); ret=0; int f=1; while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; ret*=f; } void init() { read(n); read(m); read(kk); for ( int i=1;i<=n;i++) { read(up[i]); read(dn[i]); l[i]=0; h[i]=m+1; } l[0]=0; h[0]=m+1; for ( int i=1;i<=kk;i++) { int x,ll,r; read(x); read(ll); read(r); l[x]=ll; h[x]=r; } } int ok( int i, int j) { return j>l[i]&&j<h[i]; } int dp[maxn][1005],now; void work() { for ( int i=1;i<maxn;i++) for ( int j=1;j<=1000;j++) dp[i][j]=INF; for ( int i=1;i<=m;i++) dp[0][i]=0; int fl=1, as ,ans=1e9; for ( int i=1;i<=n;i++) { fl=0; for ( int j=1;j<=m;j++) { if (j>up[i]) { if (ok(i-1,j-up[i])) dp[i][j]=min(dp[i][j],dp[i-1][j-up[i]]+1); dp[i][j]=min(dp[i][j],dp[i][j-up[i]]+1); } if (j==m) { for ( int k=up[i];k>=0;k--) { if (ok(i-1,j-k)) dp[i][j]=min(dp[i][j],dp[i-1][j-k]+1); dp[i][j]=min(dp[i][j],dp[i][j-k]+1); } } } for ( int j=l[i]+1;j<=h[i]-1;j++) { if (j+dn[i]<=m&&ok(i,j)&&ok(i-1,j+dn[i])) { dp[i][j]=min(dp[i][j],dp[i-1][j+dn[i]]); } if (i==n) ans=min(ans,dp[i][j]); if (dp[i][j]!=INF) fl=1; } if (!fl) break ; if (l[i]!=0||h[i]!=m+1) now++; } if (!fl) printf( "0\n%d\n" ,now); else { printf( "1\n" ); printf( "%d\n" ,ans); } } int main() { init(); work(); return 0; } |
45.积木大赛
差分,相当于在每个位置加或者减多少,一个加可以与一个减配对,于是把大于0的部分和小于0的部分分别绝对值加起来取max就是答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | //Twenty #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<ctime> #include<queue> const int maxn=100005; using namespace std; typedef long long LL; int n,a[maxn],b[maxn],aa,bb; void read( int &x) { int ret=0,f=1; char ch=getchar(); while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) ret=ret*10+ch- '0' ; x=ret*f; } void init() { read(n); for ( int i=1;i<=n;i++) { read(a[i]); b[i]=a[i]-a[i-1]; if (b[i]>0) aa+=b[i]; else bb-=b[i]; } aa=max(aa,bb); printf( "%d\n" ,aa); } int main() { init(); return 0; } |
46.树网的核
乍一看很难,然而数据范围表示是一道水题。
对于每个点进行一次dfs求出它到其他点的距离,这个同时求出树的直径(从某点dfs到最远点,该点再dfs到最远点);
然后直径暴力跑就可过。何况数据水得一比。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | //Twenty #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<vector> #include<cmath> #include<queue> typedef long long LL; using namespace std; const int maxn=305; int n,s,x,y,z,d[maxn][maxn],que[maxn],ql=1,qr; void read( int &x) { x=0; int f=1; char ch=getchar(); while (ch!= '-' &&(ch< '0' ||ch> '9' )) ch=getchar(); if (ch== '-' ) f=-1,ch=getchar(); for (;ch>= '0' &&ch<= '9' ;ch=getchar()) x=x*10+ch- '0' ; x*=f; } int ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1],f[maxn]; void add( int u, int v, int w) { nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w; nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w; } void init() { read(n); read(s); for ( int i=1;i<n;i++) { read(x); read(y); read(z); add(x,y,z); } } void dfs( int x, int fa, int top, int o) { if (o) f[x]=fa; for ( int i=fir[x];i;i=nxt[i]) if (to[i]!=fa) { d[to[i]][top]=d[x][top]+val[i]; d[top][to[i]]=d[to[i]][top]; dfs(to[i],x,top,o); } } int ans=1e9; void ck( int a, int b) { int as =0; for ( int i=1;i<=n;i++) { int cc=min(d[a][i],d[b][i]); for ( int j=ql;j<=qr;j++) cc=min(cc,d[que[j]][i]); as =max( as ,cc); } ans=min(ans, as ); } void cal( int xx, int yy, int lim) { int s=yy,t=xx,l=s,r=s,now=0; while (r!=t&&now+d[r][f[r]]<=lim) { now+=d[r][f[r]]; if (r!=s) que[++qr]=r; r=f[r]; } ck(l,r); while (r!=t) { now-=d[l][f[l]]; l=f[l]; ql++; int pr=r; while (r!=t&&now+d[r][f[r]]<=lim) { now+=d[r][f[r]]; if (r!=pr) que[++qr]=r; r=f[r]; } ck(l,r); } printf( "%d\n" ,ans); } void work() { int xx=0,yy=0; for ( int i=1;i<=n;i++) { if (i==xx) { dfs(i,0,i,1); for ( int j=1;j<=n;j++) { if (!yy||d[i][j]>d[i][yy]) yy=j; } } else dfs(i,0,i,0); if (i==1) { for ( int j=2;j<=n;j++) { if (!xx||d[i][j]>d[i][xx]) xx=j; } } } cal(xx,yy,s); } int main() { init(); work(); return 0; } |
----------------------------------------------------------------------------------------------------------------------------------------
原计划上周四的样子就要结束的跟着洛谷刷noip题被我拖到了现在。。去掉纯粹的入门难度水题大概就35道的样子,然而我写得并不算多顺利,足见我有弱QAQ
对noip题多少有一定感觉了吧,虽然听说今年会变难。
还有17天就noip了,一年带点的竞赛生涯大概会就此结束了,毕竟比起创造奇迹的人,世界上还是没能创造奇迹的人多得多嘛(虽然我相信水团会创造自己的奇迹)。
之前在知乎上看到一个回答,小时候美少女战士非常火,小朋友们一起玩角色扮演的时候,特别羡慕那些选粉色的女孩子,大家都是第一次出生在这个世界上,怎么就有勇气选最好的呢。
其实我自己的话以前也很难做到,后来很努力地想试一试,后来每次都失败了呀。
我从小到大最喜欢的两件事情都是呀,
累败累战,累战累败吧。
不知道我在说些什么。
现在手机欠费了,不能天天去看竞赛退役是怎么样的体验了。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· C# 13 中的新增功能实操
· 万字长文详解Text-to-SQL
· Ollama本地部署大模型总结
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(4)
· 卧槽!C 语言宏定义原来可以玩出这些花样?高手必看!