做这份模拟测试,已经崩溃了,英文看不懂,题意理解错。到结束了只a了第一题,人生陷入了低谷,于是花了一天的时间终于把不会的弄明白了,在这里写一份总结~
T1,简单的模拟,如果打枪打中一支鸟,将这个位置设为0,并向两边扩散,注意这个位置一定要有鸟。
代码~
#include<bits/stdc++.h> using namespace std; int a[30000]; int n,m; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; cin>>m; for(int i=1;i<=m;i++) { int t1,t2; cin>>t1>>t2; if(a[t1]>=t2) { int l=t2-1,r=a[t1]-t2; a[t1-1]+=l,a[t1+1]+=r; a[t1]=0; } } for(int i=1;i<=n;i++) cout<<a[i]<<"\n"; return 0; }
T2.dp的思想,我们设dp[i][t][w]表示在i个取完之后总厚度为t,上面的宽度为w,于是记忆化搜索就很好写出来啦(初始化dp为-1,为没有走过)
#include<bits/stdc++.h> #define inf 120390420 using namespace std; int w[300],t[300]; int n; int f[300][300][300]; int dp(int i,int tt,int ww) { if(tt>200||ww>200) return inf; if(i==n+1) return ww<=tt?tt:inf; int &ans=f[i][tt][ww]; if(ans>=0) return ans; return ans=min(dp(i+1,tt+t[i],ww),dp(i+1,tt,ww+w[i])); } int main() { cin>>n; memset(f,-1,sizeof(f)); for(int i=1;i<=n;i++) cin>>t[i]>>w[i]; cout<<dp(1,0,0)<<endl; return 0; }
附带同学的代码,背包的思想:将t看成费用,而w为价值,于是二分+背包就可以出来了,不过他好像没有用二分
#include<bits/stdc++.h> using namespace std; int n; int t[200],w[200]; int f[200]; int sum=0,s=0; int solve(int x) { f[0]=0; for(int i=1;i<=x;i++) f[i]=-12214019; for(int i=1;i<=n;i++) for(int j=x;j>=t[i];j--) f[j]=max(f[j],f[j-t[i]]+w[i]); return x>=(s-f[x]); } int main() { cin>>n; for(int i=1;i<=n;i++) { cin>>t[i]>>w[i];sum+=t[i];s+=w[i];} for(int i=1;i<=sum;i++) if(solve(i)) { cout<<i<<endl;break; } return 0; }
T3.就是运用数学的知识,首先我们可以推出夹在两个1-1之间的0的个数是2^(n-1),而可重集合的全排列是等于C(num,a),C(num-a,b)以此类推,于是我们利用乘法原理就可以做出来了。组合数的话用杨辉三角,起点从0开始,这也算小技巧吧,get+,由于数据比较小,不用高精度快速幂,也感觉不错~
#include<bits/stdc++.h> #define LL long long #define mod 1000000007 using namespace std; LL n,m; LL b[2000000]; LL c[2000][2000]; vector<LL> q; vector<LL> v; int Pow(int a,int b) { int ans=1; for(int i=1;i<=b;i++) ans=(ans*a)%mod; return ans%mod; } int main() { cin>>n>>m; for(int i=0;i<=1000;i++) c[i][0]=1; for(int i=1;i<=1000;i++) for(int j=1;j<=1000;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; if(m==0) {cout<<"0\n";return 0;} for(LL i=1;i<=m;i++) cin>>b[i]; b[0]=0; b[m+1]=n+1; sort(b,b+m+2); for(LL i=1;i<=m+1;i++) if(b[i]-b[i-1]>1){ q.push_back(b[i]-b[i-1]-1); if(i!=1&&i!=m+1) v.push_back(b[i]-b[i-1]-1); } LL tot=n-m, ans=1; for(LL i=0;i<q.size();i++) { ans*=c[tot][q[i]],ans%=mod; tot-=q[i]; } for(LL i=0;i<v.size();i++) ans*=Pow(2,v[i]-1),ans%=mod; cout<<ans<<endl; return 0; }
T4.就是模拟,我们可以运用巧妙地办法,只计算在1,n或1,m中的次数,根据奇偶性,其中的碰撞次数应该为m+n-2,于是我们每一次计算的时候判断边界条件就可以了~
#include<bits/stdc++.h> #define inf 12831240 #define LL long long using namespace std; LL n,m; map<LL,LL> book[300000]; LL ans=1; LL sx,sy; LL x,y; int main() { cin>>n>>m;cin>>x>>y; char s[2];cin>>s; if(s[0]==‘D‘) sx=1;else sx=-1; if(s[1]==‘R‘) sy=1;else sy=-1; LL res=n+m-2; if(x==1||y==1||x==n||y==m) book[x][y]=1,res--; LL num=0; while(1) { LL dis=inf; num++; if(num>=1293821){ cout<<"-1";return 0;} if(sx==1) dis=min(dis,n-x);else dis=min(dis,x-1); if(sy==1) dis=min(dis,m-y);else dis=min(dis,y-1); x+=sx*dis,y+=dis*sy,ans+=dis; if(x==1) sx=1;else if(x==n) sx=-1; if(y==1) sy=1;else if(y==m) sy=-1; if(book[x][y]==0) book[x][y]=1,res--; if(res==0) {cout<<ans<<endl;return 0;} } return 0; }
T5.是一道树形dp,我们枚举所有的边,然后断掉这条边之后,在剩下的两个联通块中分别找出到各个节点距离之和最小的节点,然后和ans进行比较,比较的时候注意,很多小细节要加以深思,比如说/2,*的部分。我们可以设size[x]表示以x为根节点的子树的大小,f[x]表示x到各个位置的距离,然后根据关系就可以求解了,具体看代码的dfs和find部分~
#include<bits/stdc++.h> #define maxn 124890 #define LL long long using namespace std; struct Edge{LL w,to,next;}e[maxn]; LL cnt=1,n; LL ans=1e18; LL head[maxn],f[maxn],sz[maxn]; void add(LL u,LL v,LL w) { e[++cnt].to=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } void dfs(LL x,LL fa) { f[x]=0,sz[x]=1; for(LL i=head[x];i;i=e[i].next) { LL j=e[i].to; if(j!=fa) { dfs(j,x); sz[x]+=sz[j],f[x]+=sz[j]*e[i].w+f[j]; } } } LL find(LL x,LL fa,LL &p,LL num) { p=min(p,f[x]); // cout<<x<<" "<<f[x]<<"\n"; for(LL i=head[x];i;i=e[i].next)if(e[i].to!=fa) { f[e[i].to]=f[x]+(num-2*sz[e[i].to])*e[i].w; find(e[i].to,x,p,num); } } int main() { cin>>n; for(LL i=1;i<=n-1;i++) { LL t1,t2,t3; cin>>t1>>t2>>t3; add(t1,t2,t3); add(t2,t1,t3); } LL i=2; while(i<=cnt) { dfs(e[i].to,e[i^1].to); dfs(e[i^1].to,e[i].to); LL p1=1e18,p2=1e18; find(e[i].to,e[i^1].to,p1,sz[e[i].to]); find(e[i^1].to,e[i].to,p2,sz[e[i^1].to]); LL sum=0; for(LL ii=1;ii<=n;ii++) sum+=f[ii];//表示该节点到其他节点的距离,算2倍 ans=min(ans,sum/2+sz[e[i].to]*sz[e[i^1].to]*e[i].w+p1*sz[e[i^1].to]+p2*sz[e[i].to]); i+=2; } cout<<ans<<endl; return 0; }
时间: 2024-12-22 00:23:30