2017.7.14 C组总结

本文精选四道算法竞赛题目并提供详细的解决方案,包括差分+前缀和、快速幂+排序+二分查找、状压DP及数学+模拟等方法,帮助读者掌握不同类型的算法技巧。

NO.1

题目描述:有n个长方形,给出它的左下角和右上角,求出q个点被多少个长方形覆盖(平行于x轴和y轴)

思路:差分+前缀和
这里写图片描述

代码:

var n,i,x,y,x1,y1,j,q:longint;
    a,f:array[0..3001,0..3001]of longint;
begin
  assign(input,'square.in');
  assign(output,'square.out');
  reset(input);
  rewrite(output);
  readln(n);
  for i:=1 to n do
    begin
      readln(x,y,x1,y1);
      inc(a[x,y]);
      inc(a[x1+1,y1+1]);
      dec(a[x1+1,y]);
      dec(a[x,y1+1]);
    end;
  for i:=1 to 3000 do
    for j:=1 to 3000 do
      f[i,j]:=f[i-1,j]+f[i,j-1]-f[i-1,j-1]+a[i,j];
  readln(q);
  for i:=1 to q do
    begin
      readln(x,y);
      writeln(f[x,y]);
    end;
  close(input);
  close(output); 
end.

NO.2

题目描述:给出N个无序不重复的数,再有M个询问,每次询问一个数是否在那N个数中,若在,则ans增加2^K,K为该数在原数列中的位置。由于ans过大,所以只要求你输出ans mod 10^9+7。

思路:快速幂+排序+二分
先做一遍快排,为二分作准备
那么每次读入一个数,就可以二分求出位置
求2^k次方做一遍快速幂(dalao都说可以不用跑快速幂,在前面预处理就好了)

代码:

#include<cstdio>
#include<iostream>
using namespace std;
long long ans,a[100000],x;
int n,m,l,c[100000];
void qsort(int l,int r)
{
    if (l>=r) return;
    int i=l,j=r;
    long long mid=a[(l+r)/2];
    do
    {
        while (a[i]<mid)i++;
        while (a[j]>mid)j--;
        if (i<=j)
        {
            a[0]=a[i];
            a[i]=a[j];
            a[j]=a[0];
            c[0]=c[i];
            c[i]=c[j];
            c[j]=c[0];
            i++; j--;
        }
    }
    while(i<=j);
    qsort(l,j);
    qsort(i,r);
}
int find(long long x)
{
    int l=1,r=n;
    while (l<=r)
    {
        int mid=(l+r)/2;
        if (a[mid]==x) return mid;
        if (a[mid]>x) r=mid-1;
        else l=mid+1;
    }
    return -1;
}
long long ksm(int b)
{
    long long r=1,base=2;
    while(b)
    {
        if(b&1) r=(r*base)%1000000007;
        base=(base*base)%1000000007;
        b>>=1;
    }
    return r;
}
int main()
{
    freopen("sfxx.in","r",stdin);
    freopen("sfxx.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        c[i]=i;
    }
    qsort(1,n);
    for (int i=1;i<=m;i++)  
    {
        scanf("%lld",&x);
        l=find(x);
        if (l!=-1) ans=(ans%1000000007+ksm(c[l])%1000000007)%1000000007;
    }
    printf("%lld",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

NO.3

题目描述:有l回合操作,其中第一回合是给出的,如果上一轮第i列放了棋子,那么这一轮第i列就不能放棋子,但再下一轮可以放,求在满足情况下有多少种放棋子的方案

思路:状压dp
设f[i][j]为第i轮状态为j的方案数
状态转移方程就是f[i][j]=f[i][j]+f[i-1][k](k表示为上个回合可以转换到j的数)
如果要k满足它可以转换到j,就满足j and k=0(因为and 只有在同一个位上有两个1才肯能有值,题目要没有相邻的棋子,如果=1就满足了)
那么问题就变成了求j和k的问题
首先,将第1轮的所有状态(1 shl n-1)设为1
然后,枚举i(2<=i<=l),枚举j可能到达的状态(1<=j<=1 shl n-1)
那么就只剩下k了,如果像j那样枚举,只能拿到90%
100%怎么做呢?
就用while做, 有两种情况:
①j and k=0,那么转移,k++
②就是100%的优化,如果j and k<>0 就表示这两轮在有相邻的棋子,那么k=k+j and k就把有相邻的棋子弄没了
最后的答案就是将读入的数压成十进制x,输出f[l][x]

代码:

var  n,l,i,j:longint;
     ans,k,y,x:int64;
     a:array[0..50]of longint;
     f:array[0..50,0..50000]of int64;
begin
  assign(input,'old.in');
  assign(output,'old.out');
  reset(input);
  rewrite(output);
  readln(n,l);
  y:=0;
  for i:=1 to n do
    begin
      read(a[i]);
      if i=1 then y:=1 else y:=y*2; 
      if a[i]=1 then x:=x+y;
    end;
  for i:=0 to 1 shl n-1 do f[0,i]:=1;
  for i:=1 to l-1 do
    begin
      for j:=0 to 1 shl n-1 do
        begin
          k:=0;
          while (k<=1 shl n-1) do
            begin
              if (j and k=0) then
                begin
                  f[i,j]:=(f[i,j]+f[i-1,k])mod 100000007;
                  k:=k+1;
                end;
              if (j and k>0) then k:=k+j and k;
            end;
        end;
    end;
  write(f[l-1,x]);
  close(input);
  close(output);
end.

NO.4

题目描述:有n堆,每堆的值不一定相等,现在有两个人,每个人依次取一堆,要剩下m堆,如果最后剩下的值为偶数,则后手赢,不然则先手赢

思路:数学+模拟
其实这题就是判断奇偶性,所以只用记录它的奇数个数l1,和偶数个数l2
还要定义两个变量,l和r表示先手和后手能取多少次
这题就有五种情况:
①双方都不能取(n=m),直接判断奇偶性
②如果后手能拿走所有的奇数,那么后手赢(因为只剩下偶数)
③如果后手能拿走所有的偶数,并且还剩偶数份,那么后手赢(奇数*偶数=偶数)
④如果先手能拿走所有的偶数,并且还剩奇数份,那么先手赢(奇数*奇数=奇数
⑤如果都不存在以上情况,直接判断输出

代码:

var   n,m,x,l,r,l1,l2,i:longint;
      max:int64;
begin
  assign(input,'destroy.in');
  assign(output,'destroy.out');
  reset(input);
  rewrite(output);
  while not eof() do
    begin
      readln(n,m);
      l1:=0; l2:=0;
      for i:=1 to n do
        begin
          read(x);
          if x mod 2=1 then inc(l1)
                       else inc(l2);
        end;
      readln;
      max:=l1+2*l2;
      if n=m then
        begin
          if max mod 2=1 then writeln('Earth')
                         else writeln('Three-Body');
        end
      else
        begin
          l:=0; r:=0;
          l:=(n-m+1) div 2;
          r:=(n-m) div 2;
          if (r>=l1)or(r>=l2)and((max-l2-l-r) mod 2=0) then writeln('Three-Body')
          else if (l>=l2)and((max-l2-l-r) mod 2=1) then writeln('Earth')
               else if l>r then writeln('Earth')
                           else writeln('Three-Body');
        end;
    end;
  close(input);
  close(output);
end.
### 近奇异矩阵错误的原因 在回归分析中,“Near singular matrix error. Regressors may be perfectly collinear.” 错误通常表明自变量之间存在严重的多重共线性或多变量完全共线的情况。当数据集中某些解释变量之间的关系接近于线性依赖时,设计矩阵 \(X\) 将变得接近奇异矩阵,从而无法计算其逆矩阵 \((X'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]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值