ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022高考集训3

2022-06-08 12:35:35  阅读:170  来源: 互联网

标签:int 高考 ll mx ++ 2022 include 集训 dp


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有