首页 > 其他分享 >【考后总结】8 月 CSP-S 模拟赛 7

【考后总结】8 月 CSP-S 模拟赛 7

时间:2023-08-19 15:55:39浏览次数:49  
标签:考后 int top mx dfn maxn 互换 CSP 模拟

8.19 CSP 模拟 25

给我一首歌的时间 - 周杰伦

雨淋湿了天空 毁得很讲究

你说你不懂 为何在这时牵手

我晒干了沉默 悔得很冲动

就算这是做错 也只是怕错过

在一起叫梦 分开了叫痛

是不是说 没有做完的梦最痛

迷路的后果 我能承受

这最后的出口 在爱过了才有

能不能给我一首歌的时间

紧紧的把那拥抱变成永远

在我的怀里你不用害怕失眠

哦 如果你想忘记我也能失忆

能不能给我一首歌的时间

把故事听到最后才说再见

你送我的眼泪 让它留在雨天

哦 越过你划的线我定了勇气 的终点

雨淋湿了天空 毁得很讲究

你说你不懂 我为何在这时牵手

我晒干了沉默 悔得很冲动

就算这是做错 也只是怕错过

在一起叫梦 分开了叫痛

是不是说 没有做完的梦最痛

迷路的后果 我能承受

这最后的出口 在爱过了才有

能不能给我一首歌的时间

紧紧的把那拥抱变成永远

在我的怀里你不用害怕失眠

哦 如果你想忘记我也能失忆

能不能给我一首歌的时间

把故事听到最后才说再见

你送我的眼泪 让它留在雨天

哦 越过你划的线我定了勇气 的终点

哦 你说我不该不该

不该在这时候说了我爱你

要怎么证明我没有说谎的力气

哦 请告诉我 暂停算不算放弃

我只有一天的回忆

能不能给我一首歌的时间

紧紧的把那拥抱变成永远

在我的怀里你不用害怕失眠

哦 如果你想忘记我也能失忆

能不能给我一首歌的时间

哦 把故事听到最后才说再见

你送我的眼泪 让它留在雨天

哦 越过你划的线我定了勇气 的终点

你说我不该不该

不该在这时说了爱你

要怎么证明我没力气

告诉我暂停算不算放弃

你说我不该不该

不该在这时才说爱你

要怎么证明我没有力气

我只有一天的回忆

\(\text{happyguy round}\)

去年 CSP 石家庄隔离期间的沈老师信心赛。

原 T4 是另一道 Pjudge 的题。

T1 炒币

原题:AtCoder-ARC128A Gold and Silver

正常 DP 转移是朴素的,但是乘除太大会计算不了,由于只比较大小不求结果,取 \(\ln\) 改成加减计算。

点击查看代码
int n;
int a[maxn];
db f[maxn][2];
int pre[maxn][2];
int st[maxn],top;

int main(){
    n=read();
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=0;i<=n;++i) f[i][0]=f[i][1]=-1e10;
    f[0][0]=0; 
    for(int i=1;i<=n;++i){
        if(f[i-1][0]>f[i-1][1]-log(a[i])) f[i][0]=f[i-1][0],pre[i][0]=0;
        else f[i][0]=f[i-1][1]-log(a[i]),pre[i][0]=1;
        if(f[i-1][1]>f[i-1][0]+log(a[i])) f[i][1]=f[i-1][1],pre[i][1]=0;
        else f[i][1]=f[i-1][0]+log(a[i]),pre[i][1]=1;
    }
    int now=0;
    for(int i=n;i>=1;--i){
        st[++top]=pre[i][now];
        now^=pre[i][now];
    }
    for(int i=top;i>=1;--i) printf("%d ",st[i]);
    printf("\n");
    return 0;
}

T2 凑数

原题:AtCoder-ARC139B Make N

按性价比排序,如果每次增加 \(1\) 不是最劣的,那么只用前两种一定可以凑出 \(n\)。

否则就是形如 \(Ai+Bj+k=n\),其中 \(A\) 的性价比优于 \(B\),那么 \(j\in [0,A)\),同时 \(i\in \left[0,\left\lfloor\frac{n}{A}\right\rfloor\right]\),可以根号分治,枚举其中一个,最后用 \(1\) 补齐。

点击查看代码
int t;
int n;
pii P[4];
ll ans;

int main(){
    t=read();
    while(t--){
        n=read();
        P[1].fir=1,P[2].fir=read(),P[3].fir=read();
        P[1].sec=read(),P[2].sec=read(),P[3].sec=read();
        sort(P+1,P+4,[&](pii A,pii B){
            return 1ll*A.fir*B.sec>1ll*B.fir*A.sec;
        });
        ans=llinf;
        if(P[1].fir==1) ans=1ll*n*P[1].sec;
        else if(P[2].fir==1) ans=1ll*(n/P[1].fir)*P[1].sec+1ll*(n%P[1].fir)*P[2].sec;
        else{
            if(P[1].fir<=31625){
                for(int j=0;j<P[1].fir;++j){
                    if(1ll*j*P[2].fir>n) break;
                    ll now=1ll*j*P[2].sec+1ll*((n-j*P[2].fir)/P[1].fir)*P[1].sec+1ll*((n-j*P[2].fir)%P[1].fir)*P[3].sec;
                    ans=min(ans,now);
                }
            }
            else{
                for(int i=0;i<=n/P[1].fir;++i){
                    ll now=1ll*i*P[1].sec+1ll*((n-i*P[1].fir)/P[2].fir)*P[2].sec+1ll*((n-i*P[1].fir)%P[2].fir)*P[3].sec;
                    ans=min(ans,now);
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

T3 同构

原题:CodeForces-698F Coprime Permutation *3000

肯定能意识到如果质因子集合相同的数可以互换,略微打表发现 \(n=3\) 时 \(\{1,3\}\) 可以互换,\(n=7\) 时 \(\{1,5,7\}\) 可以互换,但 \(\{1,3\}\) 不能互换了。

如果能打表打到 \(n=14\),那么这题应该就做出来了,会发现 \(\{10,14\}\) 也可以互换,但是一个特点是 \(\{10,14\}\) 互换时 \(\{5,7\}\) 也互换了,类似一个整体互换。而这个互换到 \(n=15\) 又不复存在。

可以猜想出两个互换:质因子集合相同的数集,以及倍数个数相同的质数倍数集。

前者证明比较显然,这题是不要知道具体次数的,质因子集合有交无交是判断依据,因此质因子集合相同的能任一互换。

后者证明可以这样考虑,\(p\) 的倍数之间发生的互换属于第一类互换,例如 \(n=52\) 时 \(\{26,52\}\) 可以互换,而两个质因数 \(p_1,p_2\) 倍数集合的的任意两个元素,他们质因子集合的交一定和 \(p_1,p_2\) 无关,而第一类互换和此时的整体互换都保证了除去 \(p_1,p_2\) 的质因子集合相同,那么没有影响。至于和其他不在集合内数,发现质因子集合的交也是和 \(p\) 无关的。

第一类互换每个数一定只在一个集合内出现,第二类也有这样的保证,因为事实上一定有 \(p\ge \sqrt{n}\),若 \(p<\sqrt{n}\),那么 \(\left\lfloor\frac{n}{p}\right\rfloor\) 互不相同,也就是每个数只会作为最大质因子的倍数出现。

点击查看代码
int n;
int fact[maxn];
int pr[maxn],mn[maxn];
int cnt1[maxn],cnt2[maxn];
int ans;
inline void solve(){
    fact[0]=1;
    for(int i=1;i<=n;++i) fact[i]=1ll*fact[i-1]*i%mod;
    for(int i=2;i<=n;++i){
        if(!mn[i]) pr[++pr[0]]=i,mn[i]=i;
        for(int j=1;i*pr[j]<=n&&j<=pr[0];++j){
            mn[i*pr[j]]=pr[j];
            if(i%pr[j]==0) break;
        }
    } 
    for(int i=2;i<=n;++i){
        int now=i,S=1,tmp;
        while(now!=1){
            S*=mn[now],tmp=mn[now],now/=mn[now];
            while(mn[now]==tmp) now/=tmp;
        }
        ++cnt1[S];
    }
    ++cnt2[1];
    for(int i=2;i<=pr[0];++i) ++cnt2[n/pr[i]];
    ans=1;
    for(int i=1;i<=n;++i){
        ans=1ll*ans*fact[cnt1[i]]%mod*fact[cnt2[i]]%mod;
    }
    printf("%d\n",ans);
}

int main(){
    n=read();
    solve();
    return 0;
}

原题区别在于限制了一些位置的值。

判断合法就是判断第一类互换质因子集合是否相同,第二类互换最大质因子的倍数个数是否相同、除去最大质因子后质因子集合是否相同以及整体互换是否矛盾。

计算答案可以先求出没有限制的答案,遇到一个限制就计数器作更改。

点击查看代码
int n;
int fact[maxn],inv_fact[maxn];
int p[maxn];
int pr[maxn],mn[maxn],mx[maxn];
int S[maxn];
int cnt1[maxn],cnt2[maxn];
int nxt[maxn];
int ans;
inline void linear_sieve(){
    fact[0]=1,inv_fact[0]=1;
    for(int i=1;i<=n;++i) fact[i]=1ll*fact[i-1]*i%mod;
    inv_fact[n]=q_pow(fact[n],mod-2,mod);
    for(int i=n-1;i>=1;--i) inv_fact[i]=1ll*inv_fact[i+1]*(i+1)%mod;
    mn[1]=mx[1]=1;
    for(int i=2;i<=n;++i){
        if(!mn[i]) pr[++pr[0]]=i,mn[i]=i;
        for(int j=1;i*pr[j]<=n&&j<=pr[0];++j){
            mn[i*pr[j]]=pr[j];
            if(i%pr[j]==0) break;
        }
    }
    for(int i=2;i<=n;++i){
        int now=i,tmp;
        S[i]=1;
        while(now!=1){
            S[i]*=mn[now],tmp=mn[now],now/=mn[now];
            while(mn[now]==tmp) now/=tmp;
        }
        ++cnt1[S[i]];
    }
    ++cnt2[1];
    for(int i=1;i<=pr[0];++i){
        ++cnt2[n/pr[i]];
        for(int j=1;pr[i]*j<=n;++j){
            mx[pr[i]*j]=max(mx[pr[i]*j],pr[i]);
        }
    }
}

int main(){
    n=read();
    for(int i=1;i<=n;++i) p[i]=read();
    linear_sieve();
    for(int i=1;i<=n;++i){
        if(!p[i]) continue;
        // 特判 1 的情况
        if(i==1&&p[1]==1) --cnt2[1];
        else if(i==1){
            if(mn[p[i]]!=p[i]||n/p[i]>1) return printf("0\n"),0;
            --cnt2[1];
        }
        else if(p[i]==1){
            if(mn[i]!=i||n/i>1) return printf("0\n"),0;
            --cnt2[1];
        }
        else{
            // 不合法情况分为 第二类互换不在同一集合,第二类互换除去 p 后 S 集合不同,第二类互换出现矛盾
            if(S[i]==S[p[i]]){
                if(nxt[mx[i]]&&nxt[mx[i]]!=mx[i]) return printf("0\n"),0;
                --cnt1[S[i]];
                if(!nxt[mx[i]]) --cnt2[n/mx[i]],nxt[mx[i]]=mx[i];
            }
            else{
                if(n/mx[i]!=n/mx[p[i]]) return printf("0\n"),0;
                if(S[i/mx[i]]!=S[p[i]/mx[p[i]]]) return printf("0\n"),0;
                if(nxt[mx[p[i]]]&&nxt[mx[p[i]]]!=mx[i]) return printf("0\n"),0;
                --cnt1[S[i]];
                if(!nxt[mx[p[i]]]) --cnt2[n/mx[i]],nxt[mx[p[i]]]=mx[i];
            }
        }
    }
    ans=1;
    for(int i=1;i<=n;++i){
        ans=1ll*ans*fact[cnt1[i]]%mod*fact[cnt2[i]]%mod;
    }
    printf("%d\n",ans);
    return 0;
}

T4 最近公共祖先

考虑一个节点什么时候一定可以作为 \(u\) 与一个节点的 \(\mathrm{LCA}\),答案是这个节点有至少两棵子树有黑色节点。

不妨用线段树对 DFS 序维护所有至少两棵子树有黑色节点的节点的权值最大值,再用两个 set 分别维护只有一棵子树或没有子树有黑色节点的节点,子树内节点每次产生贡献时,暴力把修改范围内只有一棵子树或没有子树有黑色节点的从 set 移动到线段树或是另一个 set,均摊 \(O(n)\) 次操作。

现在要思考的是如何不重复的把新的黑色节点 \(u\) 贡献到父亲中。我们实际要找到最深的节点 \(f\) 使得其子树内对父亲产生过贡献,那么 \(u\) 可以产生的贡献是沿到根据路径上节点一直到 \(f\)(\(f\) 的儿子并未对 \(f\) 产生过贡献)。

不妨对每条重链开树状数组,每次跳重链可以先判断这条链上有无要求的 \(f\),如果有那么在上面二分,单次复杂度 \(O(\log^2 n)\)。修改直接暴力修改,显然这样操作也是均摊 \(O(n)\) 次的。

这样查询答案时,先在线段树查询到根路径上最大值。考虑只有一棵子树有黑色节点的祖先能不能作为 \(\mathrm{LCA}\),事实上也只有最深的祖先可能有贡献,只需要判断这个祖先的儿子有没有对其产生贡献,依旧使用刚才的树状数组。

时间复杂度 \(O(n\log^2 n)\)。

点击查看代码
int n,m;
int w[maxn];
struct edge{
    int to,nxt;
}e[maxn<<1];
int head[maxn],cnt;
inline void add_edge(int u,int v){
    e[++cnt].to=v,e[cnt].nxt=head[u],head[u]=cnt;
    e[++cnt].to=u,e[cnt].nxt=head[v],head[v]=cnt;
}
int fa[maxn],dep[maxn],siz[maxn],son[maxn];
int top[maxn],ed[maxn],dfn[maxn],dfncnt,id[maxn];
set<int> S0,S1;
void dfs1(int u,int f,int d){
    fa[u]=f,dep[u]=d,siz[u]=1;
    int maxson=-1;
    for(int i=head[u],v;i;i=e[i].nxt){
        v=e[i].to;
        if(v==f) continue;
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(siz[v]>maxson) son[u]=v,maxson=siz[v];
    }
}
void dfs2(int u,int t){
    top[u]=t,ed[t]=u,dfn[u]=++dfncnt,id[dfncnt]=u;
    S0.insert(dfn[u]);
    if(!son[u]) return;
    dfs2(son[u],t);
    for(int i=head[u],v;i;i=e[i].nxt){
        v=e[i].to;
        if(v==fa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}

struct BinaryIndexTree{
#define lowbit(x) (x&-x)
    int siz;
    vector<int> sum;
    inline void build(int k){
        siz=k;
        sum.resize(k+1);
    }
    inline void update(int x){
        while(x<=siz){
            ++sum[x];
            x+=lowbit(x);
        }
    }
    inline int query_prefix(int x){
        int res=0;
        while(x){
            res+=sum[x];
            x-=lowbit(x);
        }
        return res;
    }
    inline int query_range(int l,int r){
        return query_prefix(r)-query_prefix(l-1);
    }
#undef lowbit
}B[maxn];
struct SegmentTree{
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
    int mx[maxn<<2];
    inline void push_up(int rt){
        mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
    }
    void build(int rt,int l,int r){
        if(l==r) return mx[rt]=-1,void();
        build(lson),build(rson);
        push_up(rt);   
    }
    void update(int rt,int l,int r,int p){
        if(l==r) return mx[rt]=w[id[p]],void();
        if(p<=mid) update(lson,p);
        else update(rson,p);
        push_up(rt);   
    }
    int query(int rt,int l,int r,int pl,int pr){
        if(pl<=l&&r<=pr) return mx[rt];
        int res=-1;
        if(pl<=mid) res=max(res,query(lson,pl,pr));
        if(pr>mid) res=max(res,query(rson,pl,pr));
        return res;
    }
#undef mid
#undef lson
#undef rson
}S2;

inline void update(int u){
    if(!B[0].query_range(dfn[u],dfn[u]+siz[u]-1)){
        int x=u;
        while(x){
            if(B[top[x]].query_range(1,dfn[x]-dfn[top[x]]+1)){
                int l=1,r=dfn[x]-dfn[top[x]]+1,f;
                while(l<=r){
                    int mid=(l+r)>>1;
                    if(B[top[x]].query_range(mid,dfn[x]-dfn[top[x]]+1)) f=id[dfn[top[x]]+mid-1],l=mid+1;
                    else r=mid-1; 
                }
                set<int>::iterator it=S1.lower_bound(dfn[f]),tmp;
                while(it!=S1.end()){
                    if((*it)>dfn[x]) break;
                    S2.update(1,1,n,(*it));
                    tmp=it,++it;
                    S1.erase(tmp);
                }
                it=S0.lower_bound(dfn[f]);
                while(it!=S0.end()){
                    if((*it)>dfn[x]) break;
                    S1.insert((*it));
                    tmp=it,++it;
                    S0.erase(tmp);
                }
                for(int i=dfn[f]+1;i<=dfn[x];++i) B[top[x]].update(i-dfn[top[x]]+1);
                break;
            } 
            else{
                set<int>::iterator it=S1.lower_bound(dfn[top[x]]),tmp;
                while(it!=S1.end()){
                    if((*it)>dfn[x]) break;
                    S2.update(1,1,n,(*it));
                    tmp=it,++it;
                    S1.erase(tmp);
                }
                it=S0.lower_bound(dfn[top[x]]);
                while(it!=S0.end()){
                    if((*it)>dfn[x]) break;
                    S1.insert((*it));
                    tmp=it,++it;
                    S0.erase(tmp);
                }
                for(int i=dfn[top[x]];i<=dfn[x];++i) B[top[x]].update(i-dfn[top[x]]+1);
            }
            x=fa[top[x]];
        }
    } 
    B[0].update(dfn[u]);
    S2.update(1,1,n,dfn[u]);
    set<int>::iterator it=S0.lower_bound(dfn[u]);
    if(it!=S0.end()&&(*it)==dfn[u]) S0.erase(it);
    it=S1.lower_bound(dfn[u]);
    if(it!=S1.end()&&(*it)==dfn[u]) S1.erase(it);
}
inline int query(int u){
    int res=-1;
    if(B[0].query_range(dfn[u],dfn[u]+siz[u]-1)) res=w[u];
    int x=u;
    while(x){
        res=max(res,S2.query(1,1,n,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    x=u;
    int tmp;
    while(x){
        set<int>::iterator it=S1.lower_bound(dfn[top[x]]);
        if(it!=S1.end()&&(*it)<=dfn[x]){
            it=S1.upper_bound(dfn[x]);
            --it;
            tmp=((*it)==dfn[x])?tmp:id[(*it)+1];
            if(!B[top[tmp]].query_range(dfn[tmp]-dfn[top[tmp]]+1,dfn[tmp]-dfn[top[tmp]]+1)) res=max(res,w[id[(*it)]]);
            break;
        }
        tmp=top[x],x=fa[top[x]];
    }
    return res;
}
char opt[10];

int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i) w[i]=read();
    for(int i=1,u,v;i<n;++i){
        u=read(),v=read();
        add_edge(u,v);
    }
    dfs1(1,0,0);
    dfs2(1,1);
    S2.build(1,1,n);
    B[0].build(n);
    for(int u=1;u<=n;++u){
        if(top[u]!=u) continue;
        B[u].build(dep[ed[u]]-dep[u]+1);
    }
    for(int i=1;i<=m;++i){
        scanf("%s",opt);
        int u=read();
        if(opt[0]=='M') update(u);
        else printf("%d\n",query(u));  
    }
    return 0;
}


正解是考虑每次对子树取 \(\max\),暴力枚举祖先 \(f\),每次把 \(f\) 除去 \(u\) 所在子树的部分取 \(\max\),如果此时 \(f\) 内已经有黑色节点,那么后续的操作都是重复操作,这样均摊 \(O(n)\) 次操作。

这样只需要区间取 \(\max\) 单点查询,复杂度 \(O(n\log n)\)。

标签:考后,int,top,mx,dfn,maxn,互换,CSP,模拟
From: https://www.cnblogs.com/SoyTony/p/Simulation_Problems_of_CSP-S_in_August_7.html

相关文章

  • 模拟应用网关下游系统的一些场景测试接口
    场景:构造一个返回请求参数(表单入参),请求header,设置响应header的测试demo接口框架:springboot@ResponseBody@RequestMapping("/test/api/v1")publicMapserverPostTestv1(HttpServletRequesthttpRequest,HttpServletResponsehttpResponse,@RequestHeaderMultiValueMap<Str......
  • FBM山体模拟生成
    FBM山体模拟生成引言当我们沐浴在自然山脉的美景中,岩石峰峦和蜿蜒山谷的形态总能唤起人们的惊叹。然而,要在计算机图形中精确地还原这些复杂的地形却是一项挑战。在计算机图形学和游戏开发领域,分数布朗运动(FBM)被用来模拟自然地貌,为生成逼真的山地景观提供了一种强大方法。FBM利用分......
  • vector类的模拟实现
    一、vector的介绍vector的文档介绍1、vector是表示可变大小数组的序列容器。2、就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。3、本......
  • 2023.8.18A组模拟赛总结
    T1幂矩阵这题十分巧合。题目大意是有这样一个矩阵求该矩阵的逆矩阵中每项元素的平方和,手模几个点,会发现以下结论\[(P_n)^{-1}(i,j)=\begin{cases}i^m\binomij\quadi\geqj\\0\quadi<j\end{cases}\]不难发现我们的答案即是\[\sum_{i=1}^ni^{2m}\sum_{j=1}^i\bin......
  • CSP模拟24
    yspm专场2。原神派蒙、药水泡面、医生拍门、浴室泡沫A.原神派蒙思路结论:如果序列原先就合法,答案为\(0\);否则,最多使用两个寄存器。我们对\(i\rightarrowa_i\)建边得到若干个环,我们单独考虑一个环如何操作。对于一个长度为\(4\)的数列,再包含两个寄存器,设两个寄......
  • 8.18 模拟赛小结
    前言不平衡的一集T1动态数点题意很清楚我们先思考怎么暴力搞如果一个数是\(k\)那么它一定是这个区间的最大公约数可以直接搞个ST表加二分每次枚举左端点由于gcd和二分都有\(\log\)总时间复杂度\(O(n\log^2n)\)然后就挂了30pts(((考虑优化成\(O(n\log......
  • 振弦采集仪模拟信号转数字信号的工作原理
    三河凡科科技学习飞讯振弦采集仪模拟信号转数字信号的工作原理振弦采集仪是一种非常重要的测试仪器,其主要作用是将物理系统中的震动信号转换成数字信号,并且进行进一步的信号处理和分析。本文将详细介绍振弦采集仪模拟信号转数字信号的工作原理。 1.模拟信号采集振弦采集仪......
  • 模拟实现vector
    首先要知道vector是什么vector是什么 1.vector是表示可变大小数组的序列容器。就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。本质......
  • 2023北京/杭州/深圳CSPM-3国标项目管理中级认证招生
    CSPM-3中级项目管理专业人员评价,是中国标准化协会(全国项目管理标准化技术委员会秘书处),面向社会开展项目管理专业人员能力的等级证书。旨在构建多层次从业人员培养培训体系,建立健全人才职业能力评价和激励机制的要求,培养我国项目管理领域复合型人才。  【证书含金量】 ·竞聘优先......
  • 振弦采集仪模拟信号转数字信号的工作原理
    振弦采集仪模拟信号转数字信号的工作原理振弦采集仪是一种非常重要的测试仪器,其主要作用是将物理系统中的震动信号转换成数字信号,并且进行进一步的信号处理和分析。本文将详细介绍振弦采集仪模拟信号转数字信号的工作原理。1.模拟信号采集振弦采集仪通过传感器来采集物理系统中......