A

Soltuion

这题怎么说呢?八仙过海各显神通吧。

  1. 仅针对本题而言,做法直接计算的曼哈顿距离的两倍即可。
  2. dfs/next_permutation 暴力
  3. 数据范围大一点,改一下题不能用做法1和做法2的时候,应当是状压DP。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  maxn = 1e6 + 5;

void solve(){
    int n,m,sx,sy,t;
    cin>>n>>m>>sx>>sy>>t;
    pair<int,int> a[10];
    for(int i=0;i<t;i++){
        cin>>a[i].first>>a[i].second;
    }
    sort(a,a+t);
    int ans=INF;
    do{
        int tmp=abs(sx-a[0].first)+abs(sy-a[0].second);
        for(int i=1;i<t;i++){
            tmp+=abs(a[i].first-a[i-1].first)+abs(a[i].second-a[i-1].second);
        }
        tmp+=abs(sx-a[t-1].first)+abs(sy-a[t-1].second);
        ans=min(ans,tmp);
    }while(next_permutation(a,a+t));
    cout<<"The shortest path has length "<<ans<<"\n";
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

B

Soltuion

DFS+剪枝
考虑到都是整数,且存在制约的选择范围,所以可以将R的数据范围大致确定,然后dfs枚举。
我们令下面为层,最上面为第层,则每层对应的最小

  1. 预处理每层的最小对应的最小,最小
  2. DFS再可能有解的数据范围内枚举

由于该数据范围依旧过大,会
我们考虑剪枝:

  1. 已选择的+剩下体积能转换的的最小>=已知最优解的
  2. 已选择的+所能选的最小的>=已知最优解的
  3. 已选择的+所能选的最小的>=

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  N = 1e6 + 5;

int ans=INF;
int n,m;
int mins[N],minv[N],preS[N],preV[N];

void dfs(int r,int h,int s,int v,int k){
    if(k==0){
        if(v==n) ans=min(ans,s);
        return;
    }
    if(s+2*(n-v)/r>ans) return;
    if(v+minv[k]>n) return;
    if(s+mins[k]>ans) return;
    for(int i=r-1;i>=k;i--){
        if(k==m) s=i*i;
        int mxh=min(h-1,(n-v-minv[k-1])/(i*i));
        for(int j=mxh;j>=k;j--){
            dfs(i,j,s+2*i*j,v+i*i*j,k-1);
        }
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        mins[i]=mins[i-1]+2*i*i;
        minv[i]=minv[i-1]+i*i*i;
    }
    int mx=(int)sqrt(n);
    dfs(mx,n,0,0,m);
    if(ans==INF) cout<<0;
    else cout<<ans;
    return 0;
}

C

Soltuion

DP,01背包变形

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  maxn = 1e6 + 5;
const ll  N = 4e2 + 5;

char s[N];
int f[N][N];

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin>>n>>m>>s+1;
    memset(f,0x3f,sizeof(f));
    f[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=i;j>=1;j--){
            for(int k=1;k<=j;k++){
                f[j][0]=min(f[j][0],f[j][k]);
                if(s[i]=='1') f[j][k]=min(f[j][k],f[j-1][k-1]+k);
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            if(f[i][j]<=m) ans=i;
    cout<<ans;
    return 0;
}

D

Soltuion

Tarjan求割边模板题
答案为总边数减掉割边

下面讲讲如何利用Tarjan求割边。
Tarjan求割边:
Tarjan有两个数组表示能回到的最早的时间戳的编号,表示遍历的时间戳编号。
问题关键在于如何判断是否为割边?

的时候这条边就的边即为割边,这表示当前子节点无法从其他路径回到父节点,即父节点和子节点这条边是桥。

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  N = 1e5 + 5;

int n,m,cnt,low[N],dfn[N],cut[N],ans;
vector<int> G[N];

void tarjan(int x,int fa){
    low[x]=dfn[x]=++cnt;
    for(auto c:G[x]){
        if(!dfn[c]){
            tarjan(c,x);
            low[x]=min(low[x],low[c]);
            if(low[c]>dfn[x]) ans++;
        }
        else if(c!=fa) low[x]=min(low[x],dfn[c]);//c!=fa表明不是父亲节点
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    tarjan(1,1);
    cout<<m-ans<<'\n';
    return 0;
}

E

Soltuion

高中数学题,比较,我们可以由对数函数的单调性去比。
图片说明

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  maxn = 1e6 + 5;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int x,y;cin>>x>>y;
    double u=y*log10(x),v=x*log10(y);
    if(u>v)    cout<<">";
    else if(u<v) cout<<"<";
    else cout<<"=";
    return 0;
}