1010 数学专题

1010 数学专题,订正

CF1730B. Meeting on the Line

题意:

n n n 人在坐标轴上,第 i i i 人在 X i X_i Xi 点,到 X 0 X_0 X0 时间为 ∣ X 0 − X i ∣ |X_0-X_i| X0Xi ,第 i i i 人的准备时间为 T i T_i Ti ,总时间是 T i + ∣ X 0 − X i ∣ T_i+|X_0-X_i| Ti+X0Xi

在坐标轴上找一个点使所有人到这个点的总时间最短。
误差小于 1 0 − 6 10^{-6} 106

思路:

既然给误差值了自然想到 二分 (手动滑稽)

这道题需要二分时间:

二分位置,无法证明其地点与时间的单调性,舍弃;

二分时间,取所有人的该时间内可到地点的交集;

由题知,该地点唯一;

所以最后得到的交集一定为一个长度小于 1 e − 6 1e-6 1e6 的区间,达到精度后输出其端点即可。

code:

#include<iostream>
#include<cstdio>
using namespace std;
const double EPS=1e-7;//多二分一位更放心
int T, num,pos[100001],t[100001];
double l,r,ans;
bool check(double times){
    
    
    double ll=-1e9,rr=1e9;
    for(int i=1;i<=num;i++){
    
    
        double extra=times-t[i];
        if(extra<0)return 0;
        double posl=pos[i]-extra,posr=pos[i]+extra;
        ll=max(ll,posl),rr=min(rr,posr);//不断取交集
    }
    //[ll,rr]即所有人可以到达的地点区间
    if(rr-ll>=EPS)ans=ll;//check函数不断更新ans
    return rr-ll>=EPS;
}
void solve(){
    
    
    scanf("%d",&num);
    l=r=1e9;
    for(int i=1;i<=num;i++)scanf("%d",&pos[i]);
    for(int i=1;i<=num;i++)scanf("%d",&t[i]),l=min(l,(double)t[i]);//缩小二分范围,r不知道上限,写无穷大就行
    while(r-l>=EPS){
    
    
        double mid=(l+r)/2;
        if(check(mid))r=mid;else l=mid;
    }
    printf("%lf\n",ans);//这里要用printf,改成cout就会自动四舍五入,过不了。
}
int main(){
    
    
    for(scanf("%d",&T);T--;)solve();
}

CF1612D. X-Magic Pair

手搓数据后就懂了

具体思路看注释,也可以自己手推试试

#include <iostream>
#include <cstring>
#define yes puts("YES")
#define no puts("NO")
#define ll long long//数据范围
using namespace std;
ll t,a,b,x;
void solve(ll a,ll b){
    
    
    if(a<b)swap(a,b);//通过手模数据发现由于操作具有对称性,只有a,b的数值影响结果,与a,b位置无关,
    //把大数字放前,可以去掉绝对值,方便计算。
    if(!b||x>a){
    
    no;return;}//存在两种情况不符合条件,a,b 存在 0 或 x 大于 a,b 手推易懂;
    if(a==x||b==x){
    
    yes;return;}//存在两种符合条件的,即题目意思。
    if(a%b==x%b){
    
    yes;return;}
    //手模数据,发现终会推到 (a-k*b,b) 这一步去除 k*b (k>=0) 即 a,x 存在公约数 b ,则多次操作一定能凑出x;
    solve(a%b,b);//重复操作
}
int main(){
    
    
    for(cin>>t;t--;)cin>>a>>b>>x,solve(a,b);//由于需要递归操作,读入写在函数外部
}

CF1715C. Monoblock

题意:题意

code:

#include <iostream>
using namespace std;
#define int long long
int a[100001],n,m,i,x,ans;
main() {
    
    
    cin >> n >> m;
    for (i = 1; i <= n; ++i)
        cin >> a[i];
    for (i = 1; i <= n; ++i)
        ans += (a[i] != a[i + 1]) * (n - (i + 1) + 1) * i;//初始贡献
    while (m--) {
    
    
        cin >> i >> x;
        ans -= (a[i]!=a[i - 1]) * (n - i + 1) * (i - 1);//减去原数字的贡献
        ans -= (a[i]!=a[i + 1]) * (n - (i + 1) + 1) * i;
        a[i] = x;
        ans += (a[i]!=a[i - 1]) * (n - i + 1) * (i - 1);//加上修改后数字的贡献
        ans += (a[i]!=a[i + 1]) * (n - (i + 1) + 1) * i;
        cout << ans + n * (n + 1) / 2 << '\n';//算上初始贡献
    }
}

题意:

你有任意个魔法宝石,每个魔法宝石可以分解为m个普通宝石,每个魔法宝石和普通宝石占1单位空间。现在你有一个长度为n的空间,问有多少种方案可以填满所有空间。
在这里插入图片描述
矩阵快速幂。

code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200000 + 10;
const ll mod = 1e9 + 7;
ll b[N], vis[N], in[N], num[N], a[N], t, n, m, y, k, x;
int cnt, sum, flag, f[N];
vector<int> v[N], ans;
struct mat{
    
    
    ll a[105][105];
};
mat mul(mat a, mat b){
    
    
    mat ans;
    for (int i = 1; i <= m; i++){
    
    
        for (int j = 1; j <= m; j++){
    
    
            ans.a[i][j] = 0;
            for (int k = 1; k <= m; k++){
    
    
                ans.a[i][j] += a.a[i][k] * b.a[k][j];
                if (ans.a[i][j] > mod)
                    ans.a[i][j] %= mod;
            }
        }
    }
    return ans;
}
mat ksm(mat a, ll b){
    
    
    mat ans;
    for (int i = 1; i <= m; i++)
        ans.a[i][i] = 1;
    while(b){
    
    
        if(b & 1)ans = mul(ans, a);
        b >>= 1;
        a = mul(a, a);
    }
    return ans;
}
int main(){
    
    
    cin >> n >> m;
    if (n < m)return cout << 1 << endl, 0;
    mat tr;
    for (int i = 1; i < m; i++)tr.a[i + 1][i] = 1;
    tr.a[1][1] = tr.a[1][m] = 1;
    mat ans;
    for (int i = 2; i <= m; i++)ans.a[i][1] = 1;            //行列关系不要搞错
    ans.a[1][1] = 2;                // 1,1是dp[m]的值为2
    ans = mul(ksm(tr, n - m), ans); //这里是用tr乘ans,顺序不能搞反!!!
    cout << ans.a[1][1] << endl;
}

猜你喜欢

转载自blog.csdn.net/skyflying266/article/details/127251832
今日推荐