A:二进制与一

知识点:进制转换、贪心

思路:题目的特殊性质很有帮助。发现 3 是大于等于 2 中最小的二进制全为 1 的数,所以考虑把 n 尽可能拆出更多的 3 一定是最优的。

考虑对余数分类讨论:

  • n≡0(mod3):显然全拆成 3 即可,答案为 2×n/3;
  • n≡1(mod3):考虑拆成 ⌊3n⌋−1 个 3 和两个 2,答案为 2×(⌊n/3⌋−1)+2=2*n/3;
  • n≡2(mod3):考虑拆成 ⌊3n⌋ 个 3 和一个 2,答案为 2×⌊n/3⌋+1。

参考代码

#include<bits/stdc++.h>
using namespace std;
int t,n;
int main(){
    freopen("binary.in","r",stdin);
    freopen("binary.out","w",stdout); 
    cin>>t;
    while(t--){
        cin>>n;
        if(n%3==0) cout<<n/3*2<<endl;
        else if(n%3==1) cout<<n/3*2<<endl;
        else cout<<n/3*2+1<<endl;
    }
    return 0;
}

B: 前缀逻辑值

知识点:递归

思路:数据只有0或者1,按照树的先序序列进行递归展开。遇到了对应运算符,进行左子树和右子树的展开求解。若遇到了0或者1直接返回即可。

参考代码:

#include<bits/stdc++.h>
using namespace std;
string s; 
int x=-1;
bool dfs(){
    x++;
    if(s[x]=='&')return dfs()&dfs();
    else if(s[x]=='|')return dfs()|dfs();
    else if(s[x]=='^')return dfs()^dfs();
    else if(s[x]=='1')return 1;
    else if(s[x]=='0')return 0;
}
int main(){
    freopen("logic.in","r",stdin);
    freopen("logic.out","w",stdout); 
    cin>>s;
    if(dfs())cout<<"true";
    else cout<<"false";
    return 0;
}

C:大师

知识点:动态规划

思路:求解数组中能构成的等差数列的个数,可以考虑dp[i] [j]:代表以a[i]结尾,公差为d的等差数列方案数,由于公差可正可负,那么给公差偏移20000,那么可保证所有j下标大于等于0,直接转移即可

dp[i] [d] = dp[i] [d] + dp[j] [d]+1(以 i 结尾且上一个数是 j 的公差为 d 的等差数列数量是以 j 结尾公差为 d 的等差数列数加一)

最后遍历每一个一i结尾公差为d的dp之和,不要忘记每个数单独考虑一次在累加n即可。

参考代码:

#include<bits/stdc++.h>
using namespace std;
int n,a[1001],dp[1001][40001],ans;
int mod=998244353;
//dp[i][j]以a[i]结尾,公差为d的方案数 
int main(){
    freopen("master.in","r",stdin);
    freopen("master.out","w",stdout); 
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    ans+=n;
    for(int i=1;i<=n;i++){
        for(int j=i-1;j>=1;j--){
            int d=a[i]-a[j]+20000;
            dp[i][d]+=dp[j][d]+1;
            dp[i][d]%=mod;
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=-20000;j<=20000;j++){
            ans+=dp[i][j+20000];
            ans%=mod;
        }
    }
    cout<<ans;
    return 0;
}

第四题:城市漫步

知识点:深度优先搜索

思路:对于起点到终点的必经路径使用c[i]进行标记,游玩路径使用b[i]进行标记。

第一遍搜索确定必经路径节点,也就是从起点开始搜索,一直搜索到终点,若是终点进行必经路径标记,然后一层一层往上返回进行标记。

第二边搜索确定每个游玩路径b[i]到必经路径的距离,累加在ans里面,若搜索到当前节点是游玩节点并且不是必经节点,那么需要走一个来回对于路径深度*2,然后再一次枚举now的邻接点,若当前节点now是必经路径,那么其邻接点为1的距离深度,若不是,则从当前深度deep+1递归下去即可。

最后ans为此时行走的最短距离。

参考代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int t,n,k,x,y,ans;//n总点数 k个景点 x起点 y终点
bool b[N];//b[i]=1说明i号点是目标需要游玩 
bool c[N];//c[i]=1说明i号点是必经之地必须去
vector<int> v[N];//邻接表存图 
//确定起点到终点的路径必经之点 
bool dfs(int fa,int now,int deep){
    if(now==y){
        c[now]=1; 
        ans+=deep;
        return c[now];
    }
    for(int i=0;i<v[now].size();i++){
        int nex=v[now][i];
        if(nex==fa) continue;
        c[now]|=dfs(now,nex,deep+1); 
    }
    return c[now];
}

bool dfs1(int fa,int now,int deep){
    if(b[now]&&!c[now]){
        ans+=deep*2;
        c[now]=1;
    }
    for(int i=0;i<v[now].size();i++){
        int nex=v[now][i];
        if(nex==fa) continue;
        if(c[now]==1){
            dfs1(now,nex,1);
        }else{
            c[now]|=dfs1(now,nex,deep+1); 
        } 
    } 
    return c[now];
}
int main(){
    freopen("city.in","r",stdin);
    freopen("city.out","w",stdout);
    cin>>t;
    while(t--){
        cin>>n>>k>>x>>y;
        ans=0;
        for(int i=1;i<=n;i++){ 
            v[i].clear();
            b[i]=0;
            c[i]=0;
        }
        for(int i=1;i<=k;i++){ 
            int s;cin>>s;
            b[s]=1; 
        }
        for(int i=1;i<n;i++){
            int w,z;cin>>w>>z;
            v[w].push_back(z);
            v[z].push_back(w); 
        } 
        b[x]=1;b[y]=1;
        dfs(0,x,0);
//        cout<<"必经之路: ";
//        for(int i=1;i<=n;i++){
//            if(c[i]) cout<<i<<" ";
//        } cout<<endl;
        dfs1(0,x,0); 
        cout<<ans<<endl;
    } 
    return 0;
}
Copyright ©图灵之星 2024,转载需注明出处该文件修订时间: 2025-09-06 23:09:21

results matching ""

    No results matching ""