p4998
计算所有点的不合理值取前k个相加就可以,,难点是有可能是负数,则我们就全加一倍变为正数,还要计算每个点的不合理值,如果生算的话必定会超时,用前缀和,计算下一个点时,上一个点的前缀和会有什么变化呢?这个点左边的值距离都会+1,而右边的值都会减1,根据这个求出所有点距离的前缀和,最后取前k小就可以了
题解 P4998 【信号站】 - RenaMoe's blog - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int L=1e6;
ll n,k,a[2000005],sum[2000005],l,r,ans=0;
int main(){
//freopen("in.txt","r",stdin);
cin>>n>>k;
ll x;
for(int i=1;i<=n;i++) cin>>x,a[x+L]++;
for(int i=0;i<=L+L;i++){sum[0]+=a[i]*i;}
r=n;
for(int i=1;i<=L+L;i++){
l+=a[i-1];//累加左边的个数
sum[i]=sum[i-1]+l-r;//更新前缀和
r-=a[i];//累减右边的个数
}
sort(sum,sum+L+L+1);
for(int i=0;i<k;i++) ans+=sum[i];
cout<<ans<<endl;
return 0;
}
p5603 拓扑排序
最劣情况属实折磨我了,并不是一个简简单单的倒序就可以的,所以可以再开一个队列,队列就行不需要单调的,来存放小值,大值就继续压进优先队列中,这样可以把最大的给输出,这样后面的数就不可能会使得ans++了,反例看看这个博客
题解 P5603 【小C与桌游】 - Mubuky 的博客 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int L=1e6;
int n,m,u,y,in1[500005],in2[500005];
vector<int>v1[500005],v2[500005],v;
priority_queue<int,vector<int>,greater<int> >q1;
priority_queue<int,vector<int>,less<int> >q2;
queue<int>q3;
void topo1(){
v.clear();
for(int i=1;i<=n;i++)
if(in1[i]==0) q1.push(i);
while(!q1.empty()){
int p=q1.top();q1.pop();
v.push_back(p);
for(int i=0;i<v1[p].size();i++){
int y=v1[p][i];
in1[y]--;
if(in1[y]==0) q1.push(y);
}
}
int maxx=0,ans=0;
for(int i=0;i<v.size();i++){
if(v[i]>maxx) ans++,maxx=v[i];
}
cout<<(ans>1919810?1919810:ans)<<endl;
}
void topo2(){
int maxx=0,ans=0;
for(int i=1;i<=n;i++)
if(in2[i]==0) q2.push(i);
while(!q2.empty()){
int p=q2.top();
if(p>maxx) ans++;
while(!q2.empty()){
q3.push(q2.top());
q2.pop();
}
while(!q3.empty()){
int x=q3.front();
q3.pop();
maxx=max(maxx,x);
for(int j=0;j<v2[x].size();j++){
int y=v2[x][j];
in2[y]--;
if(in2[y]==0){
if(y>maxx) q2.push(y);//这样最后从q2出来的就会是最大值,这样后面的就不会使得ans++了
else q3.push(y);//小数就继续压进q3,因为这对ans没有影响了,不需要特殊处理
}
}
}//其实就是借助q3把最大值尽可能地放在了前面,小值就直接在q3里pop掉了
}
cout<<(ans>1919810?1919810:ans)<<endl;
}
int main(){
//freopen("in.txt","r",stdin);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>y;
v1[u].push_back(y);
v2[u].push_back(y);
in1[y]++;
in2[y]++;
}
topo1();
topo2();
return 0;
}
CF1389B Array Walk
话说这是黄题吗?好难。。。dp[i][j]代表向左走了i步,在位置j时的最大分数,第一重循环z因为这样可以知道所有位置的所有情况,其次再循环n,最后k可以根据k=i*2+j-1来判断;其实知道怎样设状态怎样循环后,这个转移方程还是比较好想的,dp[i][j]=max(dp[i][j],dp[i+1][j-1]+a[i]);
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int L=1e6;
ll t,n,k,z,dp[100005][7],a[100005];
int main(){
//freopen("in.txt","r",stdin);
cin>>t;
while(t--){
cin>>n>>k>>z;
ll maxx=0;
for(int i=1;i<=n;i++) cin>>a[i];
for(int j=0;j<=z;j++)
for(int i=1;i<=n;i++){
dp[i][j]=dp[i-1][j]+a[i];
if(j&&i!=n) dp[i][j]=max(dp[i][j],dp[i+1][j-1]+a[i]);
if(i-1+j*2==k) maxx=max(maxx,dp[i][j]);
}
cout<<maxx<<endl;
}
return 0;
}
p6033 runtime队列
这题目本身已经不重要了,困扰我两个小时的原因时我自己写的代码runtime了,至于为何,在这里记录一下,队列没有元素还要他弹出元素也是会runtime的!!!!!!!!!!!!!
p6155
2的64次方取模就用unsigned ,相同的数就压进栈,然后再弹出栈计算进栈和出栈相差的时间,对这个事件排序按小到大乘以bi就可以了,虽然我对这题毫无思路。。。。
T3-修改 - gyh20 的博客 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,p[1000005],a[1000005],b[1000005];
unsigned long long ans;
struct node{
ll v,xu;
};
stack<node>q;
bool cmp(ll a,ll b){
return a>b;
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
sort(b+1,b+n+1);
ll l=1,x=1;
while(1){
if(q.empty()){
if(l<=n) x=a[l];
else break;
}
while(a[l]==x){
q.push(node{a[l],l});
l++;
}
node tmp=q.top();
q.pop();
p[tmp.xu]=x-tmp.v;//计算出栈和进栈相差的时间
x++;
}
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;i++)ans+=p[i]*b[i];
cout<<ans<<endl;
return 0;
}
p6397 二分
这道题的check函数难想,我们一开始先让d[1]加上mid,然后看看能否与下一个的距离小于等于k,然后我们先让1号和2号同时向右走一段时间,然后再让1号自己向右走正好与2号的距离为k,这样可以卡2号的极限距离,看其是否能走到与3号相差k,走不到就尽量走,之后的也一样
题解 P6397 【[COI2008] GLASNICI】 - Eclosion 的博客 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n;
double k,d[100005];
bool check(double mid){
double maxx=d[1]+mid;
for(int i=2;i<=n;i++){
if(d[i]-mid-maxx>k) return 0;
maxx+=k;
if(d[i]+mid<maxx) maxx=d[i]+mid;
}
return 1;
}
int main(){
//freopen("in.txt","r",stdin);
cin>>k>>n;
for(int i=1;i<=n;i++) cin>>d[i];
double l=0,r=d[n],mid;
while(r-l>=0.000001){
mid=(l+r)/2.0;
if(check(mid)) r=mid;
else l=mid;
}
cout<<fixed<<setprecision(4)<<l<<endl;
return 0;
}
p6433 dp
最后说一遍我是傻逼,看题解还能看错;当所有时间加起来小于m就是贪心,加不起来就是动态规划,这个是加了重循环,翻倍的那个循环,最后一定要判断谁不加倍谁加倍更好
题解 P6433 【「EZEC-1」出题】 - QwQ - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,k,dp[1005][110],ans=0,sum=0;
struct poi{
int d,x;
}a[1005];
bool cmp(poi a,poi b){return a.d>b.d;}
int main(){
//freopen("in.txt","r",stdin);
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>a[i].d>>a[i].x,sum+=a[i].x;
if(sum<=m){
sort(a+1,a+n+1,cmp);
for(int i=1;i<=k;i++) ans+=a[i].d*2;
for(int i=k+1;i<n;i++) ans+=a[i].d;
cout<<ans<<endl;
return 0;
}
for(int i=1;i<=n;i++)
for(int j=m;j>=a[i].x;j--){
for(int l=k;l>=1;l--){
dp[j][l]=max(dp[j][l],max(dp[j-a[i].x][l]+a[i].d,dp[j-a[i].x][l-1]+a[i].d*2));
ans=max(ans,dp[j][l]);
}
dp[j][0]=max(dp[j][0],dp[j-a[i].x][0]+a[i].d);
ans=max(ans,dp[j][0]);
}
cout<<ans<<endl;
return 0;
}