其他分享
首页 > 其他分享> > 2022高考集训3

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