奋斗群群赛16总结与心得

总体情况

https://vjudge.net/contest/187296
昨天在CF上打过的题目又在这里出现了,而且前两题被删掉了,后面的题我不会做差一点点就爆零了,还好我能A第4题.我去CF上瞄了一眼,掉了78分.

T1

题目

http://codeforces.com/problemset/problem/864/C

思路

我都懒得说思路了.看代码吧.我非常渣的英语说明,勿喷.中文会被坑成乱码.

#include<bits/stdc++.h>
using namespace std;//Excuse me,my English is poor.
int a,b,f,k;
int main()
{
int i,j,result=0,stop;//When the bus goes to the a point or the zero point, it can contain stop liters of gas
cin>>a>>b>>f>>k;
if (k>2&&b<2*f||k>1&&b<2*(a-f)||b<f||b<a-f) return printf("-1"),0;//The tank is so small
stop=b;
for (i=1;i<=k;i++)
  {
  if (i==k&&stop>=a) break;//If the bus goes to the final journey and has more than b liters of gas,it can go through the road
  if (i&1)//to a point
    {
    if (stop<2*a-f) result++,stop=b-a+f;//The bus can't go past the gas station twice,so it will refuel its tank 
    else stop-=a;//finish a journey
    }
  else //to zero point
    {
    if (stop<a+f) result++,stop=b-f;//The zero point is same 
    else stop-=a;
    }
  }
cout<<result;
}

T2

题目

http://codeforces.com/problemset/problem/864/D

思路

从头开始扫,出现重复的话用目前最小的没用过的数字去替换.

#include<bits/stdc++.h>
using namespace std;
const int boss=2e5;
int a[boss+10],b[boss+10],c[boss+10],d[boss+10],sum;
int main()
{
int n,i,j;
cin>>n;
for (i=1;i<=n;i++) 
  {
  scanf("%d",&a[i]);
  b[a[i]]++;
  }
for (i=1;i<=boss;i++) if (b[i]) sum++;
cout<<n-sum<<endl;
for (i=1,j=1;i<=n;i++) if (b[a[i]]>1) 
  {
  while (b[j]>0) j++;
  if (j<a[i]||c[a[i]]==1)
    {
    d[i]=j;b[j]=1;b[a[i]]--;
    }
  else d[i]=a[i],c[a[i]]=1;
  }
else d[i]=a[i];
for (i=1;i<=n;i++) printf("%d ",d[i]);
}

T3

题目

http://codeforces.com/problemset/problem/864/E

思路

这题是个简单01背包,只是要输出选择物品的编号。结构体存储4个数据,在开始背包之前一定要以物品被毁的时间从小到大排序,否则会影响最后的答案。用一个二维数组vector存储物品编号,扫dp数组的时候每当扫到最大值就更新一次选择物品的位置。

#include<bits/stdc++.h>
using namespace std;
struct loop{int st,bt,v,num;}object[2010];//savetime,broketime,value,number
vector<int> v[2010];
int dp[2010],position,i,j,n,answer;
bool cmp(loop a,loop b){return a.bt<b.bt;}
int main()
{
cin>>n;
for (i=1;i<=n;i++) scanf("%d%d%d",&object[i].st,&object[i].bt,&object[i].v),object[i].num=i;
sort(object+1,object+n+1,cmp);
for (i=1;i<=n;i++) for (j=object[i].bt-1;j>=object[i].st;j--) if (dp[j-object[i].st]+object[i].v>dp[j])//背包
  {
  dp[j]=dp[j-object[i].st]+object[i].v;
  v[j]=v[j-object[i].st];//把背包中的物品进行下一步的转移
  v[j].push_back(object[i].num);//把该物品的编号推入背包
  }
for (i=0;i<=2000;i++) if (dp[i]>answer) answer=dp[i],position=i;//求最大值,找出该最大值所在位置的所有物品编号
printf("%d\n%d\n",answer,v[position].size());
for (i=0;i<v[position].size();i++) printf("%d ",v[position][i]);
} 

T4

题目

http://codeforces.com/problemset/problem/855/B

思路

i<=j<=k,可利用数组储存m位置之前和之后最大最小的数,从头到尾一顿暴枚就可以了.一开始我看错了题目,把i<=j<=k这个条件忘了,然后直接贪心就WA了.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll boss=2e5,index=1e18;
ll a[boss+10],qianmax[boss+10],qianmin[boss+10],houmax[boss+10],houmin[boss+10];
int main()
{
int i;ll n,p,q,r,result,answer=-3*index;
cin>>n>>p>>q>>r;
for (i=1;i<=n;i++) scanf("%I64d",&a[i]);
qianmax[0]=-index;qianmin[0]=index;
for (i=1;i<=n;i++) qianmax[i]=max(qianmax[i-1],a[i]),qianmin[i]=min(qianmin[i-1],a[i]);//前缀最大最小
houmax[n+1]=-index;houmin[n+1]=index;
for (i=n;i>=1;i--) houmax[i]=max(houmax[i+1],a[i]),houmin[i]=min(houmin[i+1],a[i]);//后缀最大最小
for (i=1;i<=n;i++)
  {
  result=0;
  if (p>=0) result+=p*qianmax[i];
  else result+=p*qianmin[i];
  result+=q*a[i];
  if (r>=0) result+=r*houmax[i];
  else result+=r*houmin[i];
  answer=max(answer,result);
  }
cout<<answer;
}

T5

题目

http://codeforces.com/problemset/problem/855/C

思路

树形dp,代码还是很好理解的.利用0,1,2三个状态,0即小于k,此时0,1,2三个状态均可;1即=k,此时dp只能递推小于k的情况;同理大于k的时候能递推0,2两个状态.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll boss=1e5,mod=1e9+7;
ll n,m,k,x,a,b,answer,dp[boss+10][18][3],temp[18][3];
vector<ll> v[boss+10];
void dfs(ll father,ll xianzai)
{
int r,i,j;
dp[xianzai][0][0]=k-1,dp[xianzai][1][1]=1,dp[xianzai][0][2]=m-k;
for (r=0;r<v[xianzai].size();r++) if (v[xianzai][r]!=father)
  {
  dfs(xianzai,v[xianzai][r]);
  memset(temp,0,sizeof(temp));
  for (i=0;i<=x;i++) for (j=0;j<=i;j++)
    {
    temp[i][0]=(temp[i][0]+(dp[xianzai][i-j][0]*dp[v[xianzai][r]][j][0])%mod)%mod;
    temp[i][0]=(temp[i][0]+(dp[xianzai][i-j][0]*dp[v[xianzai][r]][j][1])%mod)%mod;
    temp[i][0]=(temp[i][0]+(dp[xianzai][i-j][0]*dp[v[xianzai][r]][j][2])%mod)%mod;
    temp[i][1]=(temp[i][1]+(dp[xianzai][i-j][1]*dp[v[xianzai][r]][j][0])%mod)%mod;
    temp[i][2]=(temp[i][2]+(dp[xianzai][i-j][2]*dp[v[xianzai][r]][j][0])%mod)%mod;
    temp[i][2]=(temp[i][2]+(dp[xianzai][i-j][2]*dp[v[xianzai][r]][j][2])%mod)%mod;
    }
  for (i=0;i<=x;i++) 
    {
    dp[xianzai][i][0]=temp[i][0];
    dp[xianzai][i][1]=temp[i][1];
    dp[xianzai][i][2]=temp[i][2];
    }   
  }
}
int main()
{
int i;
scanf("%I64d%I64d",&n,&m);
for (i=1;i<n;i++) 
  {
  scanf("%I64d%I64d",&a,&b);
  v[a].push_back(b);
  v[b].push_back(a);
  }
scanf("%I64d%I64d",&k,&x);
dfs(-1,1);
for (i=0;i<=x;i++) answer=(answer+dp[1][i][0]+dp[1][i][1]+dp[1][i][2])%mod;
printf("%I64d",answer);
}

T6

题目

http://codeforces.com/problemset/problem/855/E

思路

本题为数位DP,利用数组中数位作为状态转移之.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int boss=1e5;
ll dp[11][66][2233][2];int bit[66]; //dp数组第1位记录进制,第二位数字长度,第三位各位状态,第4位是否有前导0

ll dfs(int jinzhi,int len,int zhuangtai,int qiandao0,int xianzhi)
{
int i;
if (len==0) return !zhuangtai;
if (!xianzhi&&dp[jinzhi][len][zhuangtai][qiandao0]!=-1) return dp[jinzhi][len][zhuangtai][qiandao0];
ll result=0;
int da=xianzhi!=0?bit[len]:jinzhi-1;
for (i=0;i<=da;i++)  
  {
  if (!i&&qiandao0) result+=dfs(jinzhi,len-1,zhuangtai,1,xianzhi&(i==da));
  else result+=dfs(jinzhi,len-1,zhuangtai^(1<<i),0,xianzhi&(i==da));
  }  
return !xianzhi&&!qiandao0?dp[jinzhi][len][zhuangtai][qiandao0]=result:result;
}

ll jisuan(ll n,int jinzhi)
{
int l=0;
while (n)
  {
  bit[++l]=n%jinzhi;
  n/=jinzhi;
  }
return dfs(jinzhi,l,0,1,1);
}

int main()
{
ios::sync_with_stdio(0);cin.tie(0); //加速cin和cout
memset(dp,-1,sizeof(dp));
int t;
cin>>t;
while (t--)
  {
  int b;ll l,r;
  cin>>b>>l>>r;
  cout<<jisuan(r,b)-jisuan(l-1,b)<<endl;
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值