2017.7.12 C组总结

本文解析了四道算法题目,包括蚂蚁爬竿的最短与最长路径、整数分解以获得最大乘积、物品选取以最大化得分及军队排列组合等问题,提供了不同难度级别的解题思路与代码实现。

NO.1

题目描述: n只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行。当蚂蚁爬到竿子的端点时就会掉落。由于竿子太细,两只蚂蚁相遇时,它们不能交错通过,只能各自反向爬回去。对于每只蚂蚁,我们知道它距离竿子左端的距离xi,但不知道它当前的朝向。请计算各种情况当中,所有蚂蚁落下竿子所需的最短时间和最长时间。

思路:这里写图片描述

代码:

#include<iostream>
#include<string.h>
#include<algorithm>
#include<cstdio>
using namespace std;
#define MAXN 50000+2
int a[MAXN];
int main()
{
    freopen("t1.in","r",stdin);
    freopen("t1.out","w",stdout);
    int n,l;
    cin>>n>>l;
    int x=0,y=0,k;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        k=min(a[i],l-a[i]);if (x<k) x=k;
        k=max(a[i],l-a[i]);if (y<k) y=k;
    }
    cout<<x<<" "<<y<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

NO.2

题目描述:一个正整数一般可以分为几个互不相同的自然数的和,如3=1+2,4=1+3,5=1+4=2+3,6=1+5=2+4,…。现在你的任务是将指定的正整数n分解成m个(m>=1)互不相同的自然数的和,且使这些自然数的乘积最大。

思路:可以从2开始,枚举2+3+…i小于等于n的最大值i
剩下的值downto 加回去
再高精求出值

代码:

#include<cstdio>
#include<iostream>
using namespace std;
int n,m,l,w,k[10001],a[10000],maxn=10000;
void gaojin(int x)
{
    int g=0,k=0;
    for (int i=maxn;i>=1;i--)
    {
        g=a[i]*x+k;
        a[i]=g%10;
        k=g/10;
    }
}
int main()
{
    freopen("max.in","r",stdin);
    freopen("max.out","w",stdout);
    scanf("%d",&n);
    m=n;
    l=2;    
    if (n==4) 
    {
        printf("%d\n%d",n,n);
        return 0;
    }
    while (m>=l)
    {
        w++;
        k[w]=l;
        m-=l;
        l++;
    }
    if (m<=w) for (int i=m;i>=1;i--) k[w-i+1]++;
    else
    {
        for (int i=w;i>=1;i--) k[w-i+1]++;
        for (int i=m-w;i>=1;i--) k[w-i+1]++;
    }
    a[maxn]=1;
    for (int i=1;i<=w;i++) 
    {
        printf("%d ",k[i]);
        gaojin(k[i]);
    }
    printf("\n");
    l=1;
    while (a[l]==0) l++;
    for (int i=l;i<=maxn;i++) printf("%d",a[i]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

NO.3

题目描述:一天,还是Famer KXP,他在与他的好朋友Famer John玩一个游戏,规则如下:KXP站在起点,桌子上放置着一排物品,每个物品都有它的质量和距离起点的位置。KXP的基础分=最远物品距离*2+拿的物品的质量和,最终分数=最远物品距离*2+拿的物品的质量和*Y(Y为该物品是第Y个被拿的)KXP想提前知道自己在拿X个物品时基础分最高时最终分数为多少,若在拿K个时有多种情况能达到最高基础分则只输出X小于K时的情况(即发现有多种情况就立即结束程序),希望你帮忙解决。(K不一定被询问)

思路:贪心+堆维护
先将询问1时,的终极分数是多少
然后在每次询问,找到每次可以增加的最大值,再用堆维护

NO.4

题目描述:这种军队共有N个单位,一个接着一个排成一排,每个单位可以是士兵,或者是战车,这样的组合可以爆发出意想不到的强大战斗力;但有一点,两辆战车不能相邻,否则会发生剐蹭等不好的事故。刘邦希望知道这N个单位的军队都多少种不同的排列方法,以便在战场中随机应变。两种军队的排列方法是不同的,当且仅当某一个单位对应不同,如:第i位这种是士兵,那种是战车……

思路:30%做法:搜索
分两种情况,①当前为士兵(0),那么后面放什么都符合,dfs(dep+1,1)+dfs(dep+1,0)
②当前为战车(1),那么后面只能跟士兵,dfs(dep+1,0)
30%代码:

#include<cstdio>
#include<iostream>
int n;
int dfs(int x,int y)
{
    if (x>=n) return 1;
    if (y==0) return dfs(x+1,1)+dfs(x+1,0); 
    else return dfs(x+1,0);
}
using namespace std;
int main()
{
    freopen("siege.in","r",stdin);
    freopen("siege.out","w",stdout);
    scanf("%d",&n);
    printf("%d",dfs(1,0)+dfs(1,1));
    fclose(stdin);
    fclose(stdout);
}

70%做法:斐波那契数列
由上得出 f[i][0]+f[i][1]=f[i-1][1]+f[i-1][0]+f[i-1][0]….①
设g[i]为i长的序列排放的方案数
①转换得g[i-1]+f[i-1][0]
=g[i-1]+f[i-2][1]+f[i-2][0]
=g[i-1]+g[i-2]
就是一个明显的斐波那契数列

70%代码:

#include<cstdio>
#include<iostream>
using namespace std;
unsigned long long n,f[1000001];
int main()
{
    freopen("siege.in","r",stdin);
    freopen("siege.out","w",stdout);
    scanf("%lld",&n);
    f[1]=2;
    f[2]=3;
    for (int i=3;i<=n;i++) f[i]=(f[i-1]+f[i-2])%100000007;
    printf("%lld",f[n]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

100%思路:矩阵乘法
这里写图片描述
由此可以推出100%解法,n-1次方要用快速幂做

100%代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
long long n,a[2],b[2][2],c[2][2],d[2][2],e[2];
void ksm(long long x)
{
    memcpy(b,c,sizeof(b));
    while (x)
    {
        if (x&1)
        {
            memset(d,0,sizeof(d));
            for (int i=0;i<2;i++)
                for (int j=0;j<2;j++)
                    for (int k=0;k<2;k++)
                        d[i][j]=(d[i][j]+b[i][k]*c[k][j])% 100000007;
            memcpy(b,d,sizeof(b));
        }
        memset(d,0,sizeof(d));
        for (int i=0;i<2;i++)
            for (int j=0;j<2;j++)
                for (int k=0;k<2;k++)
                    d[i][j]=(d[i][j]+c[i][k]*c[k][j])% 100000007;
        memcpy(c,d,sizeof(c));
        x=x>>1;
    }
}
int main()
{
    freopen("siege.in","r",stdin);
    freopen("siege.out","w",stdout);
    scanf("%lld",&n);
    a[0]=2; a[1]=3;
    if (n<=2) printf("%lld",a[n-1]);
    else 
    {
        c[0][1]=c[1][0]=c[1][1]=1;
        ksm(n-2);
        for (int i=0;i<2;i++)
            for (int j=0;j<2;j++)
                e[i]=(e[i]+a[j]*b[j][i]% 100000007)% 100000007;
        printf("%lld",e[0]);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}
### 近奇异矩阵错误的原因 在回归分析中,“Near singular matrix error. Regressors may be perfectly collinear.” 错误通常表明自变量之间存在严重的多重共线性或多变量完全共线的情况。当数据集中某些解释变量之间的关系接近于线性依赖时,设计矩阵 \(X\) 将变得接近奇异矩阵,从而无法计算其逆矩阵 \((X&#39;X)^{-1}\)[^2]。 如果某个变量的列向量与其他变量合成的比例关系恒定,则该矩阵会失去满秩特性,导致行列式趋近于零或等于零[^3]。这正是引用提到的现象:“解释变量行列的最后一列全是0”,这种情况可能导致模型估计失败。 --- ### 解决方案 以下是几种常见的方法来处理 EViews 中因多重共线性引发的 “Near Singular Matrix” 问题: #### 方法一:删除冗余变量 通过逐步剔除高度相关的变量可以减少共线性的程度。具体操作如下: - 使用 **Correlation Analysis** 功能查看各变量间的相关系数表。 - 如果发现某两个或多个变量的相关系数非常高 (例如大于 |0.9|),则考虑移除其中一个变量[^4]。 ```plaintext Quick -> Group Statistics -> Correlations... ``` #### 方法二:标准化变量 有时原始单位差异过大也会加剧数值不稳定性。因此建议先对所有连续型预测因子执行均值中心化或者 z-score 转换后再重新运行 OLS 回归: \[ Z_i = \frac{X_i-\mu}{\sigma} \] 其中 \(Z_i\) 表示标准分数;\(X_i\) 是原观测值;而 \(\mu,\sigma\) 则分别代表样本平均数与标准差[^5]。 #### 方法三:引入正则化技术 对于高维特征空间下的严重共线情况,可尝试采用 Ridge 或 Lasso 等带惩罚项的方法替代传统最小二乘法。这些算法能够有效缓解参数估计过程中的波动效应并提升稳健度[^6]: Ridge Regression: \[ min ||y-Xb||_2^2+\lambda||b||_2^2 \] Lasso Regression: \[ min ||y-Xb||_2^2+\lambda||b||_1 \] 虽然Eviews本身并不直接支持上述两种高级统计建模方式,但可以通过导出数据至外部软件(如Python/R)完成进一步优化再导入回平台验证效果。 #### 方法四:增加更多独立观察值 理论上讲,只要满足基本假设条件即无完美线性关联前提下,随着样本容量增大,即使存在一定水平上的弱相关也未必会影响最终结论准确性[^7]。所以适当扩充数据库规模不失为一种简单可行策略之一。 #### 方法五:检查虚拟编码设置 特别需要注意的是,在构建哑元(dummy variables)过程中容易忽略交互作用而导致额外维度被人为加入进来形成多余约束。比如针对分类属性创建指示器序列时候应当遵循“K减去1原则”。 --- ### 总结说明 综上所述,面对此类警告提示信息时可以从以上几个角度出发逐一排查定位根本原因所在,并采取相应措施加以修正直至恢复正常运算流程为止[^8]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值