Week3学习总结

Week3学习总结

最长上升子序列

for(int i=1;i<=n;i++)
{
    f[i]=1;
    for(int j=1;j<i;j++)
        if(a[i]>a[j]) f[i]=max(f[j]+1,f[i]);
}

最长下降子序列

for(int i=1;i<=n;i++)
{
    f[i]=1;
    for(int j=1;j<i;j++)
        if(a[i]<a[j]) f[i]=max(f[j]+1,f[i]);
}

从某点向两端

//开口向上是从两端都做最长下降子序
for(int i=n;i>=n;i--)
{
    f[i]=1;
    for(int j=n;j>i;j--)
        if(a[i]<a[j]) f[i]=max(f[j]+1,f[i]);
}
//开口向下是从两端都做最长上升子序
for(int i=n;i>=n;i--)
{
    f[i]=1;
    for(int j=n;j>i;j--)
        if(a[i]>a[j]) f[i]=max(f[j]+1,f[i]);
}

Diworth定理
一个序列中下降子序列的最少划分数个数等于最长上升子序列的长度。
一个序列中上升子序列的最少划分数个数等于最长下降子序列的长度。

动态规划

在推导 dp 方程时,我们时常会感到毫无头绪,而实际上 dp 方程也是有迹可循的,总的来说,需要关注两个要点:状态,决策和转移。其中 “状态” 又最为关键,决策最为复杂。

【状态】
关于 “状态” 的优化可以从很多角度出发,思维难度及其高,有时候状态选择的好坏会直接导致出现暴零和满分的分化。

【决策】
与 “状态” 不同,“决策” 优化则有着大量模板化的东西,在各大书籍,文章上你都可以看到这样的话:只要是形如 XXXXXX 的状态转移方程,都可以用 XXXXXX 进行优化。

【转移】
“转移” 则指由最优决策点得到答案的转移过程,其复杂度一般较低,通常可以忽略,但有时也需要特别注意并作优化。

目前对dp的理解总结

dp数组的维度取决于状态变量有几个,但有时可以进行维度压缩。

循环取决于状态变量有几个,状态转移方程的数量取决于决策有几个。

状态转移方程里面绝大多数的转移都是和循环对应的方向相反的。

首先确定dp空间的一个角(如dp[1] [1]),然后通过循环使其走到相距最远的另一个角上(如dp[n] [n]),要控制每一步的行走方向(决策方向)才能达到最优解,而状态转移方程就对应了每一种决策。

回文字符串

#include<bits/stdc++.h>
using namespace std;
char a[1002];
char b[1002];
int dp[1002][1002];
int main()
{
    cin>>a+1;
    int len=strlen(a+1);
    for(int i=1,j=len; i<=len+1; i++,j--)
        b[j]=a[i];
    for(int i=1; i<=len; i++)
    {
        for(int j=1; j<=len; j++)
        {
            if(a[i]==b[j])
                dp[i][j]=dp[i-1][j-1]+1;
            else
                dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
        }
    }
    int ans=len-dp[len][len];
    cout<<ans<<endl;
    return 0;
}

数塔

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int a[N][N];
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int h;
        cin>>h;
        for(int i=1; i<=h; i++)
        {
            for(int j=1; j<=i; j++)
            {
                cin>>a[i][j];
            }
        }
        for(int i=h; i>=1; i--)
        {
            for(int j=1; j<=i;j++)
            {
                a[i][j]+=max(a[i+1][j],a[i+1][j+1]);
            }
        }
        cout<<a[1][1]<<endl;
    }
    return 0;
}

乌龟棋

#include<iostream>
#include<memory.h>
using namespace std;

int n,m;
int a[400];
int b[5]; 
int f[42][42][42][42];

int main(){
	cin >> n>>m;
	for(int i=1;i<=n;i++){
		cin >> a[i];
	}
	
	memset(b,0,sizeof(b));
	for(int i=0;i<m;i++){
		int x;
		cin >> x;
		b[x]++;
	}
	//f[i][j][k][h]表示使用i张1,j张2,,,所获得的最大分数
	f[0][0][0][0]=a[1];
	for(int i=0;i<=b[1];i++){
		for(int j=0;j<=b[2];j++){
			for(int k=0;k<=b[3];k++){
				for(int h=0;h<=b[4];h++){
					int x=i+2*j+k*3+h*4;//增加的步数
					//因为从1开始,那么下一步position为x+1,所以取x+1位置的数字 
					if(i) f[i][j][k][h]=max(f[i][j][k][h],f[i-1][j][k][h]+a[x+1]);
					if(j) f[i][j][k][h]=max(f[i][j][k][h],f[i][j-1][k][h]+a[x+1]);
					if(k) f[i][j][k][h]=max(f[i][j][k][h],f[i][j][k-1][h]+a[x+1]);
					if(h) f[i][j][k][h]=max(f[i][j][k][h],f[i][j][k][h-1]+a[x+1]);
				}
			}
		}
	} 
	
	cout<<f[b[1]][b[2]][b[3]][b[4]]<<endl;
	return 0;
}

欧拉函数

筛法求欧拉函数

void euler(int n)
{
    phi[1]=1;//1要特判 
    for (int i=2;i<=n;i++)
    {
        if (flag[i]==0)//这代表i是质数 
        {
            prime[++num]=i;
            phi[i]=i-1;
        }
        for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法 
        {
            flag[i*prime[j]]=1;//先把这个合数标记掉 
            if (i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子 
                break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次 
            }
            else phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质 
        }
    }
}

组合数

方法1:递推
C ( m , n ) = C ( m − 1 , n ) + C ( m − 1 , n − 1 ) , 运用 D P 思想直接地递推出结果 C(m,n) = C(m-1,n) + C(m-1,n-1) , 运用DP思想直接地递推出结果 C(m,n)=C(m1,n)+C(m1,n1),运用DP思想直接地递推出结果

const int N=2010,mod=1e9+7;
int c[N][N];

void init()
{
    for(int i=0;i<N;i++)
        for(int j=0;j<=i;j++)
            if(!j) c[i][j]=1;
            else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}

方法2:预处理阶乘
C ( m , n ) = m ! / n ! / ( m − n ) ! ,先预处理出 1   N 的阶乘和阶乘的乘法逆元,后运用费马小定理处理 C(m,n) = m!/n!/(m-n)! ,先预处理出1~N的阶乘和阶乘的乘法逆元,后运用费马小定理处理 C(m,n)=m!/n!/(mn)!,先预处理出1 N的阶乘和阶乘的乘法逆元,后运用费马小定理处理

typedef long long LL;
const int N=1e5+10,mod=1e9+7;
int fact[N],infact[N];

int qmi(int a,int k,int p)
{
    int res=1;
    while(k)
    {
        if(k&1) res=(LL) res*a%p;
        a=(LL)a*a%p;
        k>>=1;
    }
    return res;
}

int main()
{
    fact[0]=infact[0]=1;
    for(int i=1;i<N;i++)
    {
        fact[i]=(LL)fact[i-1]*i%mod;
        infact[i]=(LL)infact[i-1]*qmi(i,mod-2,mod)%mod;
    }
    ...
     printf("%d\n",(LL)fact[a]*infact[b]%mod*infact[a-b]%mod);
    ...
}

方法3:卢卡斯定理
带入卢卡斯公式,递归调用,得到结果。 带入卢卡斯公式,递归调用,得到结果。 带入卢卡斯公式,递归调用,得到结果。

typedef long long LL;

int qmi(int a,int k,int p)
{
    int res=1;
    while(k) 
    {
        if(k&1) res=(LL)res*a%p;
        a=(LL)a*a%p;
        k>>=1;
    }
    return res;
}

typedef long long LL;

int qmi(int a,int k,int p)
{
    int res=1;
    while(k) 
    {
        if(k&1) res=(LL)res*a%p;
        a=(LL)a*a%p;
        k>>=1;
    }
    return res;
}
int lucas(LL a,LL b,int p)
{
    if(a<p && b<p) return C(a,b,p);
    return (LL)C(a%p,b%p,p)*lucas(a/p,b/p,p)%p;
}

int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        LL a,b;
        int p;
        cin>>a>>b>>p;
        cout<<lucas(a,b,p)<<endl;
    }

    return 0;
}

方法4:分解质因子法
将分子分母的质因数都分解后消去,存在数组中 ( s u m [ i ] ) ,运用高精度乘法算出结果。 将分子分母的质因数都分解后消去,存在数组中(sum[i]),运用高精度乘法算出结果。 将分子分母的质因数都分解后消去,存在数组中(sum[i]),运用高精度乘法算出结果。

const int N = 5010;
int primes[N], cnt;
int sum[N];
bool st[N];


void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}


int get(int n, int p)
{
    int res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}


vector<int> mul(vector<int> a, int b)
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size(); i ++ )
    {
        t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    while (t)
    {
        c.push_back(t % 10);
        t /= 10;
    }
    return c;
}


int main()
{
    int a, b;
    cin >> a >> b;

    get_primes(a);

    for (int i = 0; i < cnt; i ++ )
    {
        int p = primes[i];
        sum[i] = get(a, p) - get(a - b, p) - get(b, p);
    }

    vector<int> res;
    res.push_back(1);

    for (int i = 0; i < cnt; i ++ )
        for (int j = 0; j < sum[i]; j ++ )
            res = mul(res, primes[i]);

    for (int i = res.size() - 1; i >= 0; i -- ) printf("%d", res[i]);
    puts("");

    return 0;
}

如果是大数的组合数(1e18)一般选择卢卡斯定理。
而2、4算法时间复杂度相似,区别在于是否取余。

exgcd同余方程

#include<iostream>
using namespace std;
long long exgcd(long long a, long long b, long long &x, long long &y)
{
    if (!b)
    {
        x = 1; y = 0;
        return a;
    }
    long long d = exgcd(b, a % b, y, x);
    y -= (a/b) * x;
    return d;
}

int main()
{
    long long a,b,x=0,y=0;
    cin>>a>>b;
    exgcd(a,b,x,y);
    cout<<(x%b+b)%b<<endl;
    return 0;
}

矩阵乘法

<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 502;
const ll mod = 1e9+7;
ll n, p, m;
ll a[N][N];
ll b[N][N];
ll c[N][N];
void xf()
{
    for (ll i = 0; i < n; i++)
    {
        for (ll j = 0; j < m; j++)
        {
            for (ll k = 0; k < p; k++)
            {
                c[i][j] += a[i][k] * b[k][j] % mod;
                c[i][j] %= mod;
            }
        }
    }
}
int main()
{
    cin >> n >> p >> m;
    for (ll i = 0; i < n; i++)
        for (ll j = 0; j < p; j++)
            cin >> a[i][j];
    for (ll i = 0; i < p; i++)
        for (ll j = 0; j < m; j++)
            cin >> b[i][j];
    xf();
    for (ll i = 0; i < n; i++)
    {
        for (ll j = 0; j < m; j++)
        {
            while (c[i][j] < 0)
                c[i][j] += mod;
        }
    }
    for (ll i = 0; i < n; i++)
    {
        for (ll j = 0; j < m; j++)
            cout << c[i][j]<<' ';
        cout << endl;
    }
    return 0;
}

Fibonacci第n项

#include <iostream>
using namespace std;
long long m;
void mul(int a[][2], int b[][2], int c[][2])
{
    int temp[][2] = {{0, 0}, {0, 0}};
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
            for (int k = 0; k < 2; k ++ )
            {
                long long x = temp[i][j] + (long long)a[i][k] * b[k][j];
                temp[i][j] = x % m;
            }
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
            c[i][j] = temp[i][j];
}

int f_final(long long n)
{
    int x[2] = {1, 1};
    int res[][2] = {{1, 0}, {0, 1}};
    int t[][2] = {{1, 1}, {1, 0}};
    long long k = n - 1;
    while (k)
    {
        if (k&1) mul(res, t, res);
        mul(t, t, t);
        k >>= 1;
    }

    int c[2] = {0, 0};
    for (int i = 0; i < 2; i ++ )
        for (int j = 0; j < 2; j ++ )
        {
            long long r = c[i] + (long long)x[j] * res[j][i];
            c[i] = r % m;
        }
    return c[0];
}

int main()
{
    long long n ;
    cin >> n >> m;
    cout << f_final(n-1) << endl;
    return 0;
}

exgcd中国剩余定理-曹冲养猪

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
long long n,x,y;
long long ans,N;
long long a[15],b[15];
inline long long Exgcd(long long a,long long b,long long &x,long long &y){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    long long gcd=Exgcd(b,a%b,x,y);
    long long t=x;
    x=y;
    y=t-a/b*y;
    return gcd;
}
inline long long IntChina(long long k){
    long long N=1;
    for(register int i=1;i<=k;i++)
        N*=a[i];
    for(register int i=1;i<=k;i++){
        long long m=N/a[i];
        Exgcd(m,a[i],x,y);
        ans=((ans+b[i]*m*x)%N+N)%N;
    }
    return ans;
}
int main(){
    scanf("%lld",&n);
    for(register int i=1;i<=n;i++)
        scanf("%lld%lld",&a[i],&b[i]);
    printf("%lld\n",IntChina(n));
    return 0;
}

线段树区间维护带lazy——just a hook

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 100000
struct node
{
    int w,f;
} tree[4*maxn+10];

void build(int k,int l,int r)//建树
{
    tree[k].w=1;
    tree[k].f=0;
    if(l==r)
        return ;
    int m=(l+r)/2;
    build(2*k,l,m);
    build(2*k+1,m+1,r);
    tree[k].w=tree[2*k].w+tree[2*k+1].w;
}

void down(int k,int l,int r)//这里的l,r还可以写在结构里面,那样可能更好理解
{
    tree[2*k].f=tree[2*k+1].f=tree[k].f;
    int m=(l+r)/2;
    tree[2*k].w=tree[k].f*(m-l+1);
    tree[2*k+1].w=tree[k].f*(r-m);
    tree[k].f=0;
}

void add(int k,int l,int r,int x,int y,int w)//区间更改
{
    if(l>=x&&r<=y)
    {
        tree[k].w=w*(r-l+1);
        tree[k].f=w;
        return ;
    }
    if(tree[k].f)
        down(k,l,r);
    int m=(l+r)/2;
    if(x<=m)
        add(2*k,l,m,x,y,w);
    if(y>m)
        add(2*k+1,m+1,r,x,y,w);
    tree[k].w=tree[2*k].w+tree[2*k+1].w;
}

int main()
{
    int t,n,q,ca=1;
    scanf("%d",&t);
    while(t--)
    {
        memset(tree,0,sizeof(tree));
        scanf("%d%d",&n,&q);
        int x,y,w;
        build(1,1,n);
        while(q--)
        {
            scanf("%d%d%d",&x,&y,&w);
            add(1,1,n,x,y,w);
        }
        printf("Case %d: The total value of the hook is %d.\n",ca++,tree[1].w);
    }
    return 0;
}

学习心得

本周学习平稳,并没有什么特别的地方,不过打了一次团队赛,配合还不错,不过感觉因为缺少板子导致有些题没有做出来,比如那道曹冲养猪,是一道中国剩余定理的模板题,但是因为我们都没有学过中国剩余定理就没有做出来。但是如果有板子的话应该是可以做出来的,因为题上已经有明显暗示是使用这个方面的知识了,还有A题的一道线段树,如果有板子的话应该能找到错误然后过,期间罚时和耽误的时间比较多,主要还是比赛经验不足导致的。通过这次团队赛让我们队得到了很多经验。初步划分了我们队每个成员的主要负责内容。

weixin073智慧旅游平台开发微信小程序+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
python017基于Python贫困生资助管理系统带vue前后端分离毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
weixin102旅游社交微信小程序+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打豆豆1234

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值