虚拟赛做了6个,也还可以了,由于第四题卡了一下(除数为0)有点炸,最后一题分析一下状态转移方程还是比较容易看出来用优先队列来优化
地址:http://codeforces.com/contest/1077
A. Frog Jumping
思路:签到题,只要long long即可
Code:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAX_N=1e5+5;
LL n,m,T;
int main()
{
ios::sync_with_stdio(false);
cin>>T;
LL a,b;
while(T--){
cin>>a>>b>>n;
LL t=a-b;
LL ans=t*(n/2);
if(n%2==1) ans+=a;
cout<<ans<<endl;
}
return 0;
}
B. Disturbed People
思路:遍历一遍,若a[i]满足要求则更改掉a[i+1]=0即可
Code:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAX_N=1e2+5;
int n,m,T;
int a[MAX_N];
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;++i)
cin>>a[i];
int ans=0;
for(int i=2;i<n;++i)
if(!a[i]&&a[i-1]&&a[i+1]){
++ans; a[i+1]=0;
}
cout<<ans<<endl;
return 0;
}
C. Good Array
思路:先求出所有a[i]的和Sum以及用记录a[i]的个数b[a[i]]。再遍历a[i],若t=(Sum-a[i])/2存在以及不是 t==a[i]&&b[i]==1的情况,则答案加上i.
Code:
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long LL;
const int MAX_N=1e6+5;
int n,m,T;
int a[MAX_N],b[MAX_N],d[MAX_N];
int main()
{
scanf("%d",&n);
LL Sum=0;
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
Sum+=a[i];
++b[a[i]];
}
int ans=0;
LL t;
for(int i=1;i<=n;++i)
{
t=(Sum-a[i])/2;
if(t+t==Sum-a[i]&&t<MAX_N&&b[t]){
if(t==a[i]&&b[t]==1) continue;
d[ans++]=i;
}
}
printf("%d\n",ans);
for(int i=0;i<ans-1;++i)
printf("%d ",d[i]);
if(ans) printf("%d\n",d[ans-1]);
return 0;
}
D. Cutting Out
思路:二分查找
先将x的个数按由大到小排序,再二分查找每个元素的最大个数,再按照最大个数求出答案即可
Code:
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;
const int MAX_N=2e5+5;
struct node{
int x;
int s;
bool operator<(const node &p)const{
return s>p.s;
}
};
int n,m,ni,T;
int res[MAX_N];
node d[MAX_N];
map<int,int> imap;
bool judge(int h);
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=0,x;i<n;++i)
{
cin>>x;
++imap[x];
}
ni=0;
for(auto c:imap)
d[ni++]=node{c.first,c.second};
sort(d,d+ni);
int l=0,r=d[0].s,h;
while(l<=r){
h=(l+r)/2;
if(judge(h)) l=h+1;
else r=h-1;
}
int t=0,s;
for(int i=0;i<ni;++i)
{
s=d[i].s/r;
for(int j=0;j<s;++j)
res[t++]=d[i].x;
if(t>=m) break;
}
for(int i=0;i<m-1;++i)
cout<<res[i]<<" ";
cout<<res[m-1]<<endl;
return 0;
}
bool judge(int h)
{
if(h==0) return true;//直接返回true,d[i].s/h不能为0
bool boo=true;
int t=0;
for(int i=0;i<ni;++i)
{
if(t>m||d[i].s<h) break;
t+=d[i].s/h;
}
if(t<m) boo=false;
return boo;
}
E. Thematic Contests
思路:枚举+二分查找
先将相同ai的个数按照由小到大排序(利用map)存到d[ni]中,在对于第一场比赛的题目数t进行枚举,再用二分查找2*t,最后取最大值即可
Code:
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long LL;
const int MAX_N=2e5+5;
struct node{
int x;
int s;
bool operator<(const node &p)const{
return s<p.s;
}
};
int n,m,ni,T;
node d[MAX_N];
map<int,int> imap;
bool judge(int h);
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=0,x;i<n;++i)
{
cin>>x;
++imap[x];
}
ni=0;
for(auto c:imap)
d[ni++]=node{c.first,c.second};
sort(d,d+ni);
int ans=0,Sum,t,si,l;
for(int k=1;k<=n;++k)
{
Sum=0; t=k; l=0;
si=lower_bound(d+l,d+ni,node{0,t})-d;
while(si<ni){
Sum+=t; t*=2;
l=si+1;
si=lower_bound(d+l,d+ni,node{0,t})-d;
}
ans=max(ans,Sum);
}
cout<<ans<<endl;
return 0;
}
F1. Pictures with Kittens (easy version)
思路:dp
dp[i][j]:表示第j次时取第i个图片时的最大价值
那么 dp[i][j]=max{dp[k][j-1]} (i-m<=k<=i-1) ,其中m为最大间距
时间复杂度为O(n*m*s) s取的图片数量,由于n,m,s<=200,因此不会超时
Code:
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long LL;
const int MAX_N=2e2+5;
int n,m,s;
int a[MAX_N];
LL dp[MAX_N][MAX_N];
LL pre[MAX_N][MAX_N];
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=1;i<=m;++i)
dp[i][1]=a[i];
for(int i=2;i<=n;++i)
for(int j=1;j<=s;++j)
{
for(int k=i-m;k<i;++k)
if(k>0&&dp[k][j-1]) dp[i][j]=max(dp[i][j],dp[k][j-1]);
if(i<=m&&j==1) continue;
if(dp[i][j]) dp[i][j]+=a[i];
}
LL ans=0;
for(int i=n-m+1;i<=n;++i)
ans=max(ans,dp[i][s]);
if(!ans) ans=-1;
printf("%lld\n",ans);
return 0;
}
F2. Pictures with Kittens (hard version)
思路:dp+优先队列
这题较上一题的数据范围变为了5000,因此O(n*m*s)会超时,对于状态转移方程
dp[i][j]=max{dp[k][j-1]} (i-m<=k<=i-1) ,其中m为最大间距
分析一下发现,其中max(dp[k][j-1]}是可以用优先队列优化的,用优先队列Q维护{dp[i][j-1],i}(以dp[i][j-1]按大的优先),当求dp[i][j]时,将Q.top()的元素下标大于i-m的出队列,再取Q.top()即可
Code:
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
typedef long long LL;
typedef pair<LL,int> pr;
const int MAX_N=5e3+5;
int n,m,s;
int a[MAX_N];
LL dp[MAX_N][MAX_N];
priority_queue<pr> Q;
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
for(int i=1;i<=m;++i)
dp[i][1]=a[i];
for(int j=2;j<=s;++j)
{
while(!Q.empty()){
Q.pop();
}
for(int i=1;i<=n;++i)
{
while(!Q.empty()&&Q.top().second<i-m){
Q.pop();
}
if(!Q.empty()){
dp[i][j]=Q.top().first+a[i];
}
if(dp[i][j-1]) Q.push(pr{dp[i][j-1],i});
}
}
LL ans=0;
for(int i=n-m+1;i<=n;++i)
ans=max(ans,dp[i][s]);
if(!ans) ans=-1;
printf("%lld\n",ans);
return 0;
}