ABC375

A - Seats(模拟)

题意:给定字符串s,求i和i+2为#,i+1为.的个数

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;cin>>n;
    string s;cin>>s;
    int ans=0;
    for(int i=0;i<n-2;i++){
        if(s[i]=='#'&&s[i+1]=='.'&&s[i+2]=='#')ans++;
    }
    cout<<ans<<endl;
}

B - Traveling Takahashi Problem(模拟)

题意:依次访问xi,yi然后返回原点,从a,b到c,d的代价为sqrt((a-c)²+(b-d)²)

分析:每次用cd记录上次的位置

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;cin>>n;
    double ans=0;double a,b,c=0,d=0;
    for(int i=1;i<=n;i++){
        cin>>a>>b;
        ans+=sqrt((c-a)*(c-a)+(d-b)*(d-b));
        c=a,d=b;
    }
    ans+=sqrt(c*c+d*d);
    printf("%.20f\n",ans);
    return 0;
}

C - Spiral Rotation(模拟)

题意:给定n×n的网格,一共n/2次操作,对i和n+1-i之间的所有整数对 x,y ,用单元格 (x,y) 的颜色替换单元格 (y,N+1−x)的颜色

分析:每个方格有4种替换,即旋转一周,计算每个方格需要几次替换也就是k

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;cin>>n;
    char a[n+10][n+10];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];
        }
    }
    char b[n+10][n+10];
    int k;
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            k=min(abs(n-i),abs(n-j))+1;
            k=min(k,min(i,j));
        //  if(k==0)k=1;
        //  cout<<k<<endl;
            if(k%4==0)b[i][j]=a[i][j];
            else if(k%4==1)b[i][j]=a[n+1-j][i];
            else if(k%4==2)b[i][j]=a[n+1-i][n+1-j];
            else if(k%4==3)b[i][j]=a[j][n+1-i];
        }
    }
    //j=n+1-i
    //i=n+1-j 
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cout<<b[i][j];
        }
        cout<<endl;
    }
    return 0;
}

D - ABA(枚举)

题意:给定字符串,找出三个字符的回文个数

分析:用mpc记录当前字符之前出现的个数,用mp记录之前每个点相加的值,特殊情况是当前面一个字符与当前字符相同时要对mp和mpc进行处理。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
//int mp[N];
int main(){
    string s;cin>>s;
    s='-'+s;
    map<char,ll>mpc,mp;
    ll ans=0;
    for(int i=1;i<s.size();i++){
        char x=s[i];
        if(s[i-1]!=x&&mpc[x]>=1){
            ll a=i*mpc[x]-mp[x]-mpc[x];
            ans+=a;
        }
        else if(s[i-1]==x&&mpc[x]>=1){
            ll a=i*(mpc[x]-1)-(mp[x]-(i-1))-(mpc[x]-1);
            ans+=a; 
        }
        mp[x]+=i;
        mpc[x]++;
    }
    cout<<ans<<endl;
    
    return 0;
}

E - 3 Team Division(dp)

题意:有n个人分成三组,第i个人属于ai小组,强度为bi,一个团队的强度被定义为所有成员强度的总和。是否有可能让零个或更多个人交换团队,从而使所有团队的实力相等。求最少需要几个人换。

分析:用二维dp记录每次经过一个人所有的dp变化

代码:

#include <bits/stdc++.h>
using namespace std;
template<class T, class U> inline bool chmin(T& a, const U& b) {
    if (a > b) {
        a = b;
        return true;
    }
    return false;
}
int main() {
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) cin >> a[i] >> b[i];
    int sum = accumulate(b.begin(), b.end(), 0);
    if (sum % 3 != 0) {
        cout << "-1\n";
        return 0;
    }
    int A = 501;//总和<1500 每个队伍最大范围不超过500
    int inf = 1000000000;
    vector<vector<int>> dp(A, vector<int>(A, inf));
    dp[0][0] = 0;
    for (int i = 0; i < n; i++) {
        vector<vector<int>> ep(A, vector<int>(A, inf));//每次重新定义,作为存储中间过程的容器
        int e = b[i];
        for (int j = 0; j < A; j++) {//dp[j][k]表示 第i个信息对应的队1和队2的值
            for (int k = 0; k < A; k++) {
                if (a[i] == 1) {//队1
                //若加上改点不超出数据范围 更新ep为当前数值对应的最小步骤
                    if (j + e < A) chmin(ep[j + e][k], dp[j][k]);
                    if (k + e < A) chmin(ep[j][k + e], dp[j][k] + 1);
                    chmin(ep[j][k], dp[j][k] + 1);//分配给队3操作数+1
                } else if (a[i] == 2) {//队2
                    if (j + e < A) chmin(ep[j + e][k], dp[j][k] + 1);
                    if (k + e < A) chmin(ep[j][k + e], dp[j][k]);
                    chmin(ep[j][k], dp[j][k] + 1);
                } else {//队3
                    if (j + e < A) chmin(ep[j + e][k], dp[j][k] + 1);
                    if (k + e < A) chmin(ep[j][k + e], dp[j][k] + 1);
                    chmin(ep[j][k], dp[j][k]);
                }
            }
        }
        dp = move(ep);//更新dp为当前b[i]处理后的
    }
    int res = dp[sum / 3][sum / 3];//若该情况重新赋值,说明存在 则输出
    cout << (res == inf ? -1 : res) << '\n';
    
    return 0;
}

F - Road Blocked(最短路)

题意:ai城市与bi城市相连,长度为ci。给定q个查询,1 i:道路i关闭,2 x y打印x道y的最短距离,如果没有就输出-1.

分析:先得到删除完边的答案,然后倒叙每次加一条边输出最短路

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5, M = 300 + 10;
const long long inf = 1e18;
int n, m, q;
struct node {
    int u, v, w;
} e[N];
pair<int, int> qu[N];
bool vis[N];
int f[M][M];
void Solve() {
    cin >> n >> m >> q;
    for(int i=1;i<=m;i++) {
        int u, v, w;
        cin >> u >> v >> w;
        e[i] = {u, v, w};
    }
    for(int i=1;i<=q;i++) {
        int opt, x, y; cin >> opt;
        if(opt == 1) cin >> x, qu[i] = {x, inf}, vis[x] = 1;
        else cin >> x >> y, qu[i] = {x, y};
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i != j) f[i][j] = inf;
        }
    } 
    for(int i=1;i<=m;i++){
        if(!vis[i]) f[e[i].u][e[i].v] = f[e[i].v][e[i].u] = e[i].w;
    }
    //得到删除边后的答案
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
            }
        }
    }
    vector<int> ans;
    for(int i= q;i>= 1;i--) {//倒序恢复
        if(qu[i].second == inf) {//如果为删除边操作 判断是否能成为最短路的一部分
            int u = e[qu[i].first].u, v = e[qu[i].first].v;//得到边的两端uv
            f[u][v] = f[v][u] = min(f[u][v], e[qu[i].first].w);//为边赋值
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){//该边有作用的两种可能
                    f[i][j] = min(f[i][j], min(f[i][u] + f[u][v] + f[v][j], f[i][v] + f[v][u] + f[u][j]));
                }
            }       
        }
        else{
            ans.emplace_back((f[qu[i].first][qu[i].second] >= inf ? -1 : f[qu[i].first][qu[i].second]));
        }
    }
    reverse(ans.begin(), ans.end());
    for(auto p : ans) cout << p << '\n';
}
signed main() {
​
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
​
        Solve();
​
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值