2022高考集训3
作者:互联网
2022高考集训3
6月7日
前言:
我们先写第三天的,因为第二天的我现在还有三道题没改完,笑死了,众生平等日。好了,姑且不去说它。6日晚上因为改题改不出来就吃巧克力,结果一不留神就吃了7,8块那种甜到发腻的白巧,结果晚上那个嗓子就崩溃了,我咽个唾沫都有一种灼烧感,一晚上就没睡好。早上起来都说不了话了。7号考试上午我就一直灌水,灌啊灌,然后接着灌,接着灌完继续灌。早上吃饭回来新放的一桶水,他们基本都没有怎么喝,让我自己干了半桶,当然效果是显著的,我现在嗓子已经不是那么疼了,但是感冒还没好且愈发严重了。。。。。
又因为对巧克力有恐惧了,加上ljx说byw特别喜欢吃巧克力,所以就中午就送了一盒给ljx,让他送给byw,我还特地给他那盒心形的没拆封的,这本来打算送myh的。byw也让ljx带坏了,两人见了我,都来一句王队。我就莫名有种感觉,btw跟着ljx喊王队的时候两个人真的很有夫妻相啊,我倒是挺祝愿他俩一直走下去的。扯远了,我们回去
因为一直灌水+上厕所,所以题也没有怎么好好写了,可能状态也确实是不好,最后还因为废弃的数组没删结果因为它re了40分
贴下成绩
rk8,可以说是非常不满意的,加上re的四十是rk3,但还是和rk1有差距,rk1AK了,又因为rk1是某人(好吧就是WinersRain),所以我不太想接受这个现实,就没截它,又因为第三天这次考得几道题洛谷上都有,所以就直接截图我自己博客就不加密了
T1
Watching Fireworks is Fun
这个题是个单调队列优化DP,首先可以看出是个DP,因为从不同的位置跑到某个位置获得的幸福度都是不一样的,肯定是要一层层的转移出来,他可不是越近越好,他可能这个近了,下个再跑就困难了,所以不能每次贪心的走最近,一定要dp去循环(这是351238提出的疑惑)。
dp[i][j]第i个烟花释放时在j位置可以获得的最大幸福,i只和i-1,可压一维
那么转移方程就是dp[i][j]=max(dp[i-1][j+-t*d])+幸福值,很明显,+-d*t的值是不变的,所以我们没有必要去开个k再循环,直接对于同一个i的不同j,单调队列维护一个max(dp[i-1][k])即可
复杂度是O(n*m)可过,我考场正反走两遍,j-d*t到j和j+d*t到j,这样滑动,我后来又想了想,其实没必要,绝对值就解决了,但后来也懒得改了,WinersRain好像就只扫了一遍,这个题一开始开了个wor数组以t为下标,是最开始得一种思路,后来改了也忘了删,结果t直接1e9那个数组re了卡我40分
查看代码
//Watching Fireworks is Fun
//啥也别想了,DP,而且单调优化
//这一秒转移过来不同的距离,单调优化
//这两周光做这个了,都快透了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mx=1500000+1000;
int n,m;
ll d;
ll dp[5][mx];//dp[i][j]第i秒不对 是 (第i个烟花释放时)在j位置可以获得的最大幸福,i只和i-1,压一维
struct Node{
ll a;
ll b;
ll t;
}fw[mx];
int wor[mx];
int wor1[mx];
bool vis[mx];
ll sum[mx];//单调优化老数组了
int q[mx];
int l=1,r=0;
ll ans=9999999999999;//上次我可吃大亏了
//总不能真万亿幸福吧直接升天?
void Solve(){
scanf("%d%d%lld",&n,&m,&d);
int T=0;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=m;++i){
ll a,b,t;
scanf("%lld%lld%lld",&a,&b,&t);
fw[i].a=a;
fw[i].b=b;
fw[i].t=t;
// wor[t]=b;
// wor1[t]=a;
// T=max(T,t);
sum[i]=sum[i-1]+b;
// printf("%lld\n",sum[i]);
}
for(int i=1;i<=n;++i){
dp[1][i]=abs(fw[1].a-i);
}
int pd=0;
int pp=1;
for(int i=2;i<=m;++i){
if(i%2==0){
pd=2;
pp=1;
}
else {
pp=2;
pd=1;//这个操作属实不符合我的水平
}
memset(dp[pd],0x3f,sizeof(dp[pd]));//这里千万被忘啊啊啊啊啊啊啊
ll x=(fw[i].t-fw[i-1].t)*d;//用烟花轮,可跨越的距离
l=1,r=0;
//每次都必须轮j,m*n大概可以
for(int j=1;j<=n;++j){
while(l<=r && j-q[l]>x)l++;//先距离
while(l<=r && dp[pp][j]<=dp[pp][q[r]])r--;
q[++r]=j;
dp[pd][j]=min(dp[pd][j],dp[pp][q[l]]+abs(fw[i].a-j));
}
l=1,r=0;
//这里有最大跳跃距离那个题的思想
//他可以从前从后两次来,看着一样,其实不太一样,大概不太一样
//总不能是我dp定义丑了吧,不能吧
for(int j=n;j>=1;--j){//其实据我推算,倒序的话,应该直接一维就行
//但是怎么说,怕写挂不是,还是开个二维
while(l<=r && q[l]-j>x)l++;
while(l<=r && dp[pp][q[r]]>=dp[pp][j])r--;
q[++r]=j;
dp[pd][j]=min(dp[pd][j],dp[pp][q[l]]+abs(fw[i].a-j));
}
}
int en=0;
if(m%2==0)en=2;
//这里真的很丑啊,一定学二进制
else en=1;
for(int i=1;i<=n;++i){
ans=min(ans,dp[en][i]);
}
ll an=sum[m]-ans;
// printf("%lld ans=%lld\n",sum[m],ans);
printf("%lld\n",an);
//我样例直接1A,别这样,我害怕
/* for(int i=1;i<=m;++i){
for(int j=1;j<=n;++j){
//那这个d就要乘上时间t了
//wor是不变的,变的是k
//不对啊
//md这是第一题的难度嘛
//奶牛那个题,正难则反
//我不去维护答案,我去维护,奶牛要工作
//所以维护工作损耗,我要幸福,所以维护幸福损耗
//就直接维护ai-x呗,同奶牛一样,最后的总要求b是一样的
dp[i][j]=max(dp[i-1][j+ -d])
//+ -d 在j-d <= k <=j+d 里维护一个k
//它+d其实应该再倒着来一遍,不然不太好写
}
} */
/* for(int i=1;i<=T;++i){
for(int j=1;j<=n;++j){ //t*n还是离谱,就是得拿烟花轮
for(int k=j-d;k<=j+d;++k){//拿时间跳?拿烟花跳?
dp[i][j]=max(dp[i][j],dp[i-1][k]+wor[i-1]-abs(wor1[i-1]));//就这?????????
}
}
}*/
}
int main(){
// freopen("data.in","r",stdin);
// freopen("out.out","w",stdout);
freopen("fire.in","r",stdin);
freopen("fire.out","w",stdout);
Solve();
return 0;
}
我再贴下WinersRain的
查看代码
#include<cstdio>
#include<cstring>
#include<string>
#define WR WinterRain
#define int long long
#define Dream signed
using namespace std;
const int WR=1001000,INF=1152921504606846976;//皮一下2^60
struct FireWork{
int a,b,t;
}fire[WR];
int n,m,d;
int ans;
int tmp[WR],dp[WR];
int que[WR];
int read(){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=(s<<3)+(s<<1)+ch-48;
ch=getchar();
}
return s*w;
}
Dream main(){//想起Dream那次烟花火箭送Muffin Team上天
freopen("fire.in","r",stdin);
freopen("fire.out","w",stdout);
n=read(),m=read(),d=read();
for(int i=1;i<=m;i++){
fire[i].a=read(),fire[i].b=read(),fire[i].t=read();
}
for(int i=1;i<=m;i++){
memcpy(tmp,dp,sizeof(dp));//本来我想开循环赋值的
//但是想到上次T2爆零
//爷即使TLE也不用循环了
if(fire[i].t==fire[1].t){//其实看着后面的单调队列这个有点多余了
for(int j=1;j<=n;j++){//但是以防万一加上吧
dp[j]=tmp[j]+fire[i].b-abs(fire[i].a-j);
}
continue;
}
//这么一看普通动规还过不了n*m^2
//希望我的复杂度算的没错(
//得单调队列优化???别吧
int l=1,r=0;
int k=1;//k表示在哪个位置
int dis=(fire[i].t-fire[i-1].t)*d;//dis表示在两次烟花之间可以跑多远
for(int j=1;j<=n;j++){
while(k<=min(dis+j,n)){//总不能跑出去吧
while(l<=r&&tmp[k]>=tmp[que[r]]) r--;//单调队列存储的是地点
que[++r]=k;
k++;
}//我害怕它会被卡成n^2......
while(l<=r&&j-dis>que[l]) l++;//必须能从j点跑到l
dp[j]=tmp[que[l]]+fire[i].b-abs(fire[i].a-j);
}
}
ans=-INF;
for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
printf("%lld",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
T2
Perform巡回演出
我当时考场做嗨了,应该是2,4简单,1,3难,A了2,4的不少,A 1,3的没几个,我是除了rk1之外唯一一个把1,3A了的人,主要T3有意思,我就做了两个小时,回来也没细细分析就直接去做T1了,拿想到T2,T4这么简单
这个没啥好所的,一个普通DP,显然出的东西,就是题面挺复杂,我考后改的时候因为dp[][]数组的i,j大小和定义反了,就一直改不过去,气死了
查看代码
//Perform巡回演出
//“艺术家”!
//这没有办法跑最短路,所以只能是个DP
//而且n<=10,但状压也不好写啊,那就应该是个普通
//dp[i][j]= 第i天在城市j的最小值?
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mx=4000;
struct Node{
int d;
int moy[40];
//20*20*40=400*40=16000 ok
}fly[50][2000];
ll dp[1010][20];//也是,这一天只和上一天有关,压一维 ,time也不大,没有必要压
void clear(){
memset(dp,0,sizeof(dp));
//fly不清空大概没有问题吧,我说应该
}
void Solve(){
int cnt=0;
// printf("kkkkkkkkkk\n");
while(1){
cnt++;
int n,k;
scanf("%d%d",&n,&k);
if(n==0 && k==0)break;
// auto nn=n*(n-1);
for(auto i=1;i<=n;++i){
int pd=0;
for(auto j=1;j<=n-1;++j){
// printf("j=%d\n",j);
auto jj=j;
if(pd==1)jj++;
if(i==jj){
pd=1;
jj++;
}
int d;
scanf("%d",&d);
// printf("kk %d\n",d);
fly[i][jj].d=d;
// printf("f[%d][%d]=%d\n",i,jj,fly[i][jj].d);
for(auto k=1;k<=d;++k){
int x;
scanf("%d",&x);
// printf("kkk %d\n",x);
fly[i][jj].moy[k]=x;
}
}
// printf("i=%d\n",i);
}
//这个题怎么这么简单啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
//但凡我没有做T3做两个半小时
//这个题这不秒切?
//后悔了,应该先做T2,再做T4,再T1,T3
//而不是切完T3,T1之后 连分析T2的时间都没有
memset(dp,0x3f,sizeof(dp));
// dp[1][1]=0;
for(int i=2;i<=n;++i){
if(fly[1][i].moy[1]==0)continue;
dp[1][i]=fly[1][i].moy[1];
}
for(auto i=2;i<=k;++i){
// printf("kkk i=%d\n",i);
for(auto j=1;j<=n;++j){
// printf("kk j=%d\n",j);
for(auto k=1;k<=n;++k){
// printf("ooo k=%d\n",k);
if(k==j)continue;
// if(fly[k][j])
// printf("pppppppppppppppppp\n");
// printf("i=%d fly[k]=%d\n",i,fly[k][j].d);
int t=i%fly[k][j].d;
// printf("kkkkkkkkkkkkkkk\n");
if(t==0)t=fly[k][j].d;
if(fly[k][j].moy[t]==0)continue;
dp[i][j]=min(dp[i][j],dp[i-1][k]+fly[k][j].moy[t]);
// printf("dp[%d][%d]=%lld\n",i,j,dp[i][j]);
}
}
}
// printf("kkkkkkkkkkk\n");
ll anss=99999999999;
auto ans=anss;//auto 不太能通过具体的数值推导到ll,它只能是l int
/* for(int i=1;i<=n;++i){
ans=min(dp[k][i],ans);
}*/
ans=dp[k][n];
if(ans>=99999999){
printf("0\n");
}
else printf("%lld\n",ans);
}
}
int main(){
freopen("perform.in","r",stdin);
freopen("perform.out","w",stdout);
Solve();
return 0;
}
T3
枪战Maf
这个题我一看就兴趣来了,然后瞎搞了两个多小时搞出来了。下午讲题的时候我特地跟WinersRain说我想讲这个题,干饭了下午再写
标签:int,高考,ll,mx,++,2022,include,集训,dp 来源: https://www.cnblogs.com/Yi-smtwy/p/16354722.html