做这份模拟测试,已经崩溃了,英文看不懂,题意理解错。到结束了只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;
}