总体情况
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;
}
}