【思维题】数学式子推导

对一些给出限制条件的题,一眼可能数据量很大或者直接不好想,可以化式子找出限制条件或者规律。
遇到就会总结到这里,持续更新。

P2789 直线交点数

  • 求交点数的种数
  • n条中有p条平行,剩下(n-p)条与p条一定相交,交出来p*(n-p)个点,这是固定的
  • 剩下的(n-p)再求种数—>递归
const int N=1e3+10;
int ans=0;
bool f[N];
void find(int n,int cnt){
    if(n==0){
        if(!f[cnt])ans++;//如果这一种之前没有
        f[cnt]=1;
    }else{
        for(int p=n;p>=1;p--){//平行线个数枚举
            find(n-p,p*(n-p)+cnt);//讨论n-p个的数目
        }
    }
}
void solve(){
    int n;
    cin>>n;
    find(n,0);
    cout<<ans;
}

2051D 二分+离散化

  • 推式子 x ≤ s u m − a i − a j ≤ y x\leq sum-a_i-a_j\leq y xsumaiajy
  • 可得到 s u m − a i − y ≤ a j ≤ s u m − a i − x sum-a_i-y\leq a_j\leq sum-a_i-x sumaiyajsumaix,枚举 a i a_i ai可以找出对应 a j a_j aj,记录个数即可
  • a j a_j aj用二分法lower_bound(第一个大于等于目标的数)确定左右边界
  • 记录个数用前缀和优化
const int N=2e5+10;
// int a[N],b[3*N];
vector<int>axis;
int find(int aim){
    return lower_bound(axis.begin(),axis.end(),aim)-axis.begin();
}
void solve(){
    int n,x,y,sum=0;
    // memset(a,0,sizeof a);
    // memset(b,0,sizeof b);
    //使用memset会超时
    axis.clear();
    axis.push_back(-1e18);
    cin>>n>>x>>y;
    vector<int>a(n+1),b(3*n+1);
    //用来记录轴上的点:a中每个点 和 每个a[i]对应a[j]的左右界 
    forr(i,1,n){
        cin>>a[i];
        sum+=a[i];
    }
    forr(i,1,n){
        axis.push_back(a[i]);
        axis.push_back(sum-x-a[i]);
        axis.push_back(sum-y-a[i]);
    }
    //对数轴离散化
    sort(axis.begin(),axis.end());//使用unique先排序
    axis.erase(unique(axis.begin(),axis.end()),axis.end());//unique返回不重复数的末端
    forr(i,1,n)b[find(a[i])]++;//记录a中每个数位置
    forr(i,1,3*n){//求前缀和  3*n因为之前向axis中放入3*n个数
        b[i]+=b[i-1];
    }
    int cnt=0,rest=0;
    forr(i,1,n){//遍历记个数
        cnt+=b[find(sum-x-a[i])]-b[find(sum-y-a[i])-1];//前缀和优化
        if(sum-2*a[i]>=x&&sum-2*a[i]<=y){
            rest++;//记录i=j个数
        }
    }
    cout<<((cnt-rest)>>1)<<endl;
}

使用memset超时 对2e5的空间反复赋值/声明
2e5*1e4=2e9 计算机每秒1e8
必然会超时
所以用动态数组 用多少空间申请多少

1520D 化式子优化

思路

  • 数据范围2e5 O(n2)做法超时
  • 题中条件 i < j , a [ j ] − a [ i ] = j − i i<j,a[j]-a[i]=j-i i<ja[j]a[i]=ji
  • 等式移项 a [ j ] − j = a [ i ] − i a[j]-j=a[i]-i a[j]j=a[i]i
const int N=2e5+10;
int a[N];
void solve(){
    int n;
    cin>>n;map<int,int>m;
    forr(i,1,n){
        cin>>a[i];
        m[a[i]-i]++;
    }
    int cnt=0;
    for(auto i:m){
        int t=i.second;
        if(t>1)cnt+=(t*(t-1))/2;
    }
    cout<<cnt<<endl;
    return;
}

1541B 化式子优化

题意

思路

  • O(n2)暴力做法超时
    forr(i,1,n){
        forr(j,i+1,n){//这个可以优化 不必i+1~n全遍历

        }
    }
  • 优化:题中 a [ j ] × a [ i ] = i + j a[j]\times a[i]=i+j a[j]×a[i]=i+j 已知 i i i j = a [ j ] × a [ i ] − i j=a[j]\times a[i]-i j=a[j]×a[i]i
  • a[j]枚举1,2,3,…直到 j = a [ j ] × a [ i ] − i > = n j=a[j]\times a[i]-i>=n j=a[j]×a[i]i>=n

代码

void solve(){
    int n;cin>>n;
    vector<int>a(n+1);
    forr(i,1,n)cin>>a[i];
    int ans=0;
    forr(i,1,n){
        for(int j=a[i]-i;j<=n;j+=a[i]){
            if(j<i+1)continue;
            if(a[j]*a[i]==i+j)ans++;
        }
    }
    cout<<ans<<endl;
}

2041B

  • w+b个点摆 n ( n + 1 ) 2 \frac{n(n+1)}{2} 2n(n+1)的三角形
  • 不管黑白, n 2 + n − 2 ( w + b ) = 0 n^2+n-2(w+b)=0 n2+n2(w+b)=0的根取floor是 n ′ n' n最多的行数
  • 考虑黑白,1~ n ′ n' n少的颜色总能在根的条件下凑满行,多的颜色补齐其他行
void solve(){
    int w,b;
    cin>>w>>b;
    double d=w+b;
    double n=floor((sqrt(1+8*d)-1)/2.0);
    cout<<n<<endl;
}

父子局

在这里插入图片描述
用x表示y
1 n = 1 x + 1 y {1\over n}={1\over x}+{1\over y} n1=x1+y1 y = n x x − n y={{nx}\over {x-n}} y=xnnx
y应该是个整数,最简单的就是 x = n + 1 x=n+1 x=n+1,那么 y = n 2 + n y=n^2+n y=n2+n
再限制x,y不同

void solve(){
    int x,y,n;
    cin>>n;
    x=n+1;
    y=n*n+n;
    if(x==y)cout<<-1<<' '<<-1<<endl;
    else cout<<x<<' '<<y<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值