七月份信息课总结

七月份信息课总结

算法记录

线性代数:

线性代数是一种用线性思维解决代数问题的方法,常见的有向量、矩阵等。学习过程中,老师讲解了点乘、叉乘以及向量用矩阵的表示方法,还有矩阵快速幂在加速斐波那契的实现。这个知识点与数学的关系很强,需要良好的数学基础和活跃的数学思维。现在的题目可能局限于二维向量,将来可能会用到三位向量,所以还需熟练掌握三维向量的计算与运用。

数论(这是信竞生和数竞生都最难跨出的一步):

其实,我对数论的理解也只是云里雾里。目前只是背下几个板子,然后对一些简单的少有一点点理解。我的数学老师说他数论没学好,所以不能跟我讲(dog) 所以说,目前对数论的学习还是停留在背诵板子

动态规划(DP万岁!!!

以前认为DP很难,但是后面随着数学基础的加深,发现其实DP并不难。我甚至发现了一条万能的DP转移方程(当然是在不考虑优化的情况下)即:有多少个未知量就定义多少维度(数组开不下的话可以考虑vector,因为vector可以根据每次输入的值进行开数组的大小,可以多骗一点分),其值就是要求的值。这样一来,至少DP题目的50%分数是可以得到的。并且,对后期的优化也很有帮助。实际上,还可以用记搜,MLE别找我(dog)

组合数学(恶心,但我很喜欢)

记得OI上有一句经典的名言“组合数学瞎暴力”,但其实组合数学并不恐惧。组合数学无非4种:加法原理,乘法原理,组合,排列。当有多个物体进行排列(组合)时,每个物品的排列(组合)数相乘,是乘法原理;当求不同阶段的排列(组合)数之和时,排列(组合)数相加,是加法原理。在乎顺序是排列,否则是组合。我们只需根据题目进行分析,问题就可以迎刃而解了

贪心

记得刚刚学OI时,第一次接触贪心,就将其与DP混淆,其实贪心的决策是一个阶段性的决策,而DP是一个全局性的决策。DP强调的是两个字“全局”,所以说DP的题目也满足一个前置要求:无后效性(以后的决策不能影响当前的状态);而贪心强调当前,所以他不在乎以后如何。(例如:左边地上有100元,但是100元后只有1分钱,右边地上有1块钱,但是之后有1000元;贪心会选择左边,而DP会选择右边)所以说,只有那种全局要最优值一定要当前最优值的才能用贪心算法

好题记录

P1962 斐波那契数列

这一题是运用了矩阵快速幂优化斐波那契。我们知道: F i − 1 + F i − 2 = F i F_{i-1}+F_{i-2}=F_i Fi1+Fi2=Fi
然后可以推出
[ F n − 1 F n − 2 ] ∗ [ 1 1 1 0 ] = [ F n F n − 1 ] \begin{equation*}\begin{bmatrix}F_{n-1}&F_{n-2}\end{bmatrix}\end{equation*}*\begin{equation*}\begin{bmatrix} 1& 1\\1 & 0\end{bmatrix}\end{equation*}= \left[\begin{array}{c}F_n & F_{n-1}\end{array}\right] [Fn1Fn2][1110]=[FnFn1]
所以:
在这里插入图片描述
标算:

#include<iostream>
#include<string.h>
using namespace std;
#define ll long long
const ll MOD=1e9+7;
ll n;
struct mat{
	ll a[3][3];
	mat(){memset(a,0,sizeof(a));}
	mat operator*(const mat &b){
		mat res;
		for(ll i=1;i<=2;i++){
			for(ll j=1;j<=2;j++){
				for(ll k=1;k<=2;k++){
					res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]) % MOD;
				}
			}
		}
		return res;
	}
}ans,base;
void init(){
	base.a[1][1]=base.a[1][2]=base.a[2][1]=1;
	ans.a[1][1]=ans.a[1][2]=1;
}
void q(ll b){
	while(b){
		if(b&1)ans=ans*base;
		base=base*base;
		b>>=1;
	}
}
int main(){
	cin>>n;
	if(n<=2){
		cout<<1<<"\n";
		return 0;
	}	
	init();
	q(n-2);
	cout<<ans.a[1][1]%MOD<<"\n";
	return 0;
} 

P6064 [USACO05JAN] Naptime G

这是一道DP的题目,看到题目首先发现有三个未知量:当前时间已睡觉时长当前是否睡,要求的是效用值之和,所以就可以推出状态转移方程: d p [ i ] [ j ] [ 0 ] = m a x ( d p [ i − 1 ] [ j ] [ 0 ] , d p [ i − 1 ] [ j ] [ 1 ] ) d p [ i ] [ j ] [ 1 ] = m a x ( d p [ i − 1 ] [ j − 1 ] [ 0 ] , d p [ i − 1 ] [ j − 1 ] [ 1 ] + u i ) dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1])\\dp[i][j][1]=max(dp[i-1][j-1][0],dp[i-1][j-1][1]+u_i) dp[i][j][0]=max(dp[i1][j][0],dp[i1][j][1])dp[i][j][1]=max(dp[i1][j1][0],dp[i1][j1][1]+ui) i i i表示当前是第 i i i个小时, j j j表示已睡 j j j小时, 0 0 0表示当前没睡, 1 1 1表示当前这个小时在睡,所以这个问题就解决啦
【注意】:由于不知道最后一小时是不是在睡,所以第一个小时睡觉的情况需要分类讨论
标算:

#include<iostream>
#include<string.h>
#include<cstdio>
using namespace std;
const int MAXN=3835;
int n,b;
int u[MAXN];
int f[MAXN][MAXN][2];
int ans;
int main(){
    cin>>n>>b;
    for(int i=1;i<=n;i++)cin>>u[i];
    // for(int i=1;i<=n;i++)cout<<u[i]<<" ";
    memset(f,-0x3f,sizeof(f));
    f[1][1][1]=f[1][0][0]=0;
    for(int i=2;i<=n;i++){
        f[i][0][0]=f[i-1][0][0];
        for(int j=1;j<=b;j++){
            f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
            f[i][j][1]=max(f[i-1][j-1][1]+u[i],f[i-1][j-1][0]);
        }
    }
    ans=max(f[n][b][0],f[n][b][1]);
    memset(f,-0x3f,sizeof(f));
    f[1][1][1]=u[1];
    f[1][0][0]=0;
    for(int i=2;i<=n;i++){
        f[i][0][0]=f[i-1][0][0];
        for(int j=1;j<=b;j++){
            f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
            f[i][j][1]=max(f[i-1][j-1][1]+u[i],f[i-1][j-1][0]);
        }
    }
    cout<<max(ans,f[n][b][1])<<"\n";//即判断最后一小时睡和不睡的最优值
    return 0;
    // cout<<ans<<"\n";
    return 0;
}

P1223 排队接水

这是一道经典的贪心题,因为每个人的排队时间之和想要最少,就得让他们从小到大排序
直接上代码:

#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1005;
struct node{
    int date,num;
};
int n;
node ti[MAXN];
bool cmp(node x,node y){
    return x.date<y.date;
}
int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> ti[i].date;
        ti[i].num=i;
    }
    sort(ti + 1, ti + 1 + n,cmp);
    long long ans = 0;
    for (int i = 1; i <= n; i++)
        cout << ti[i].num << " ";
    cout << "\n";
    for (int j = n ; j >= 1; j--)
    {
        int i = n - j;
        ans += ti[i].date * j;
    }
    printf("%.2lf", ans*1.0 / n);
    return 0;
}

这就是近几周的好题记录

总结

近两周刷体面较广,但存在不够精细化的问题。平时老师布置的问题要落到实处,才能刚进一步。

  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值