zoukankan      html  css  js  c++  java
  • noip 真题班刷题记录及总结思考

    进度一览

    2019牛客暑期NOIP真题班提高组7-图论

    2019牛客暑期NOIP真题班普及组3-枚举1

    2019牛客暑期NOIP真题班提高组6-树

    2019牛客暑期NOIP真题班提高组5-DFS

    2019牛客暑期NOIP真题班普及组2-模拟2

    2019牛客暑期NOIP真题班提高组4-贪心

    2019牛客暑期NOIP真题班提高组3-数学

    2019牛客暑期NOIP真题班普及组1-模拟1

    2019牛客暑期NOIP真题班提高组2-二分

    2019牛客暑期NOIP真题班提高组1-模拟

    2019牛客暑期NOIP真题班普及组10-DP2

    2019牛客暑期NOIP真题班普及组9-DP1

    2019牛客暑期NOIP真题班普及组8-贪心

    2019牛客暑期NOIP真题班普及组7-数学

    2019牛客暑期NOIP真题班普及组6-排序

    2019牛客暑期NOIP真题班普及组5-字符串处理

    2019牛客暑期NOIP真题班提高组10-DP3

    2019牛客暑期NOIP真题班提高组9-DP2

    2019牛客暑期NOIP真题班普及组4-枚举2

    2019牛客暑期NOIP真题班提高组8-DP1

    听课目标:

    • 训练自己的专注程度,2x要求跟上思路,注意力高度集中
    • 我并不希望这么好的参考题你是按照yxc的步伐一步一步做出来的,首先自己读题,自己思考,自己打代码。如果遇到瓶颈再看他的思路,然后自己写代码,如果实现起来实在有问题,标注该算法,然后课下自己搞。
    • 检验这堂课是否有成效的标准是:此题的整个思维模型,数据范围及算法的推导,代码实现,在考场上我能够完全思考到位嘛

    9.28 PJ DP1

    数字游戏

    prework:

    • 环形DP->区间DP(数组开大两倍)

    • 数学意义下的取模需要变负为正再取模

    • 状态表示:f[L][R][i]LR的区间选了i组的乘积最大值,同样的,`g[L][R][i]`LR的区间选了i组的乘积最小值

      • 集合:
    • 状态转移:

    首先考虑f[l][r][i]如何计算,关键是寻找“集合划分的依据”,划分依据一般选取“最后一步的操作”,所以这里我们可以按最后一部分的位置来将f[l][r][i]所表示的所有方案划分成若干类:

    最后一段是sum[l+i-1...r]的所有划分方案;

    最后一段是sum[l+i...r]的所有划分方案;

    ...

    最后一段是sum[r...r]的所有划分方案;

    如果最后一段是sum[k...r],

    那么这一类的最大值是 f[l][k-1][i-1]*sum[k~r],其中sum()计算某一段数的和模10的余数。

    最终枚举所有长度是n的区间,取最大值/最小值即可。

    //2019/09/28
    const int N=110,M=10;
    
    int f[N][N][M],g[N][N][M];
    int a[N],sum[N];
    int n,m;
    
    inline int get_sum(int l,int r){
    	int res=sum[r]-sum[l-1];
    	while(res<0)res+=10;
    	return res%10;
    }
    
    int main(){
    	rd(n),rd(m);
    	rep(i,1,n){
    		rd(a[i]);
    		a[i+n]=a[i];
    	}
    	rep(i,1,2*n)sum[i]=sum[i-1]+a[i];
    	rep(i,1,m)
    		rep(len,i,n)
    			rep(l,1,n){
    				int r=l+len-1;
    				if(i==1)f[l][r][i]=g[l][r][i]=get_sum(l,r);
    				else{
    					f[l][r][i]=INT_MIN;
    					g[l][r][i]=INT_MAX;
    					rep(k,l+i-1,r){
    						int t=get_sum(k,r);
    						f[l][r][i]=max(f[l][r][i],f[l][k-1][i-1]*t);
    						g[l][r][i]=min(g[l][r][i],g[l][k-1][i-1]*t);
    					}
    				}
    			}
    	int maxx=INT_MIN,minn=INT_MAX;
    	rep(i,1,n){
    		maxx=max(maxx,f[i][i+n-1][m]);
    		minn=min(minn,g[i][i+n-1][m]);
    	}
    	printf("%d
    %d
    ",minn,maxx);
    	return 0;
    }
    

    开心的金明

    01背包裸题;

    • 总钱数相当于背包总容量;
    • 每件物品的价格相当于体积;
    • 每件物品的价格乘以重要度相当于价值;

    守望者的逃离

    首先比较跑步和放技能哪个更快:

    • 跑步:平均一秒 1717 米
    • 放技能:平均2.5秒恢复10点魔法,再加一秒闪烁时间,一共是3.5秒可以移动60米, 所以平均每秒 17又1/7米

    所以放技能稍快一些。

    因此当我们有充足的放技能时间时,一定要放技能,所以只有最后一小段没时间放技能的时候,才会用跑步的方式。

    求解:

    f[i]表示用i的时间,最多可以跑多远。

    先求出只用闪烁技能时,每秒最多可以跑多远。

    再用跑步的方式来“插缝”,递推出结合两种方式时,每秒最多可以跑多远。

    //2019/09/28
    const int N=300010;
    int B,S,T;
    int f[N];
    
    int main(){
    	rd(B),rd(S),rd(T);//B:蓝,S:需要逃跑的距离,T:仅剩的时间 
    	rep(i,1,T){
    		if(B>=10){
    			B-=10;//掉蓝
    			f[i]=f[i-1]+60;
    		}
    		else {
    			B+=4;//回蓝,这时站住不动
    			f[i]=f[i-1];
    		}
    	}
    	rep(i,1,T){
    		f[i]=max(f[i],f[i-1]+17);
    	}
    	if(f[T]>=S){
    		rep(i,1,T){
    			if(f[i]>=S){
    				puts("Yes");
    				printf("%d",i);
    				break;
    			}
    		}
    	}
    	else{
    		puts("No");
    		printf("%d",f[T]);
    	}
    	return 0;
    }
    

    子矩阵咕咕咕

    PJ5 字符串处理

    乒乓球

    #include<bits/stdc++.h>
    using namespace std;
    
    inline void work(string s,int score){
    	int a=0,b=0;
    	for(int i=0;i<s.size() && s[i]!='E';++i){
    		if(s[i]=='W')a++;
    		else b++;
    		if(max(a,b)>=score && abs(a-b)>=2){///////////////////////////// 
    			printf("%d:%d
    ",a,b);
    			a=b=0;
    		}
    	}
    	printf("%d:%d
    ",a,b);
    }
    
    int main(){
    	string str,line;
    	while(cin>>line)str+=line;
    	work(str,11);
    	puts("");
    	work(str,21);
    	return 0;
    }
    

    ISBN 号码

    #include<bits/stdc++.h>
    using namespace std;
    char ss[1<<21],*p1=ss,*p2=ss;
    inline char gc(){return p1==p2 && (p2=(p1=ss)+fread(ss,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    template <typename T>inline void rd(T &x){x=0;char c=gc();int f=0;while(!isdigit(c)){f|=c=='-';c=gc();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}x=f?-x:x;}
    #define rep(i,a,b) for(int i=(a);i<=(b);++i)
    #define dwn(i,a,b) for(int i=(a);i>=(b);--i)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define ee(i,u) for(int i=head[u];i;i=e[i].next)
    
    int wei,ans;
    int main(){
    	#ifdef WIN32
    	freopen("isbn.txt","r",stdin);
    	#endif
    	string s;
    	cin>>s;
    	for(int i=0;i+1<s.size();++i){
    		if(s[i]=='-')continue;
    		wei++;
    		if(s[i]=='X')ans+=wei*10;
    		else ans+=wei*(s[i]-'0');
    	}
    	ans%=11;
    	char t='X';
    	if(ans<10)t=ans+'0';
    	if(s.back()==t)puts("Right");
    	else {
    		s.back()=t;
    		cout<<s;
    	}
    	return 0;
    }
    

    多项式输出

    #include<bits/stdc++.h>
    using namespace std;
    
    int main(){
    	int n;cin>>n;
    	for(int i=n;i>=0;--i){
    		int a;scanf("%d",&a);
    		if(a==0)continue;
    		
    		if(i<n && a>0)printf("+");//不是首项 
    		else if(a<0)printf("-");
    		
    		a=a<0?-a:a;
    		
    		if(a>1 || i==0)printf("%d",a);//系数>1 || 是常数项 才输出 
    		if(i>0)printf("x");//不是常数项都输出x 
    		if(a>0 && i>1)printf("^%d",i);//不是末尾两项 && 系数不为0 
    	}
    	return 0;
    } 
    

    PJ DP3 10.22

    传球游戏

    算法:DP,环形DP

    复杂度 O(N* M)

    SOL:

    不妨设小蛮在0号,所有人的编号是0∼n−1。

    状态表示 f[i, j]

    • 集合:第j次传球后球在第i号同学手里的方案数
    • 属性:集合中元素的数量;

    状态计算:

    • f[i, j]
      

      所表示的集合可以划分成两个子集:

      • 从左边传过来的集合大小是f[i-1,j-1]
      • 从右边传过来的集合大小是f[i+1,j+1]
    • f[i,j]等于两个子集的元素数之和。

    注意当i==0j==n-1时需要特殊处理边界(因为是环状的)。

    最终答案就是f[0][m]

    const int N=35;
    int f[N][N];//第j次传球后球在第i号同学手里的方案数
    int n,m;
    
    int main(){
        #ifdef WIN32
        freopen("a.txt","r",stdin);
        #endif
        rd(n),rd(m);
        f[0][0]=1;//设小蛮是第0号
        rep(j,1,m)
            rep(i,0,n-1)
                f[i][j]=f[(i-1+n)%n][j-1]+f[(i+1)%n][j-1];
        printf("%d",f[0][m]);
        return 0;
    }
    

    摆花

    算法知识点:DP,多重背包问题,背包问题求方案数

    复杂度:O((n^{2}a))

    问题转化:

    • 将花盆数量看作背包容量;
    • 将花看作物品,体积是1,第 i 种物品最多选 (a_i) 个;
    • 问题:将背包装满的方案数是多少?

    这是典型的多重背包求方案数问题:

    • 状态表示:f[i,j] 表示前i个物品,总体积是j的方案数;
    • 状态计算:f[i,j]=f[i-1,j]+f[i-1,j-1]+...+f[i-1,j-a[i]]
    const int N=110,mod=1000007;
    int f[N],a[N];
    int n,m;
    
    int main(){
        rd(n),rd(m);
        rep(i,1,n)rd(a[i]);
        f[0]=1;
        rep(i,1,n){
            dwn(j,m,0)
                rep(k,1,min(a[i],j))
                    f[j]=(f[j]+f[j-k])%mod;
        }
        printf("%d
    ",f[m]);
        return 0;
    }
    
  • 相关阅读:
    苑举正相关视频
    pdf怎么转换成word
    Qt架构图及模块分析介绍
    读残雪的《趋光运动 : 回溯童年的精神图景》笔记
    Qt之美(一):D指针/私有实现
    十大美国大学网络公开课
    网络公开课和MOOC资源
    网络课程网站
    Qt源码学习之路(2) QCoreApplication(1)
    xshell如何导入.xsh 文件
  • 原文地址:https://www.cnblogs.com/sjsjsj-minus-Si/p/11634629.html
Copyright © 2011-2022 走看看