Codeforces Round #675 (Div. 2) A - D

A. Fence

题意

为了组成一个四边形,给定三边的长度,求最后一个边的长度

思路

我们可以想一下,当一个边固定,其余两个边分别在这个边的两个端点,且边在一边,只有有这个边的角度越大,第三个边越大,当为180°,就会成为一个直线,所以只需要小于三边之和就可以满足不是一个直线的情况,且为最大的可能,必然满足情况

代码

#include
 
using namespace std;
#define int long long
signed main(){
     
    int T;
    cin>>T;
    while(T--){
     
        int a,b,c;
        cin>>a>>b>>c;
        cout<<(a + b + c - 1)<<endl;
    }
    return 0;
}

B. Nice Matrix

题意

给定一个矩阵,为了使矩阵的行和列都满足回文串的性质,每次操作可以个任意一个数加一或减一,求最小操作数

思路

我们可以想象一下回文串的性质,所以一个点要和算他在内的四个点相同(奇数可能为两个个或一个),即求四个点相同的最小步数,和货仓选址是一个道理,只需给他的四份之一的点遍历一遍就可以了

代码

#include
#include
#include
using namespace std;
#define int long long
const int N = 110;
int a[N][N];
 
signed main(){
     
    int T;
    cin>>T;
    while(T--){
     
        int n,m;
        cin>>n>>m;
        for(int i = 1;i<=n;i++){
     
            for(int j = 1;j <= m;j++) cin >>a[i][j];
        }
        int ans = 0;
        for(int i = 1,ii = n;i<=(n + 1)/2;i++,ii--){
     
            for(int j = 1,jj = m;j<=(m + 1)/2;j++,jj--){
     
                int b[4];
                b[0] = a[i][j],b[1] = a[i][jj],b[2] = a[ii][j],b[3] = a[ii][jj]; // 对应的4个点
                sort(b,b + 4);
                int x = b[1];
                int res = abs(b[0] - b[1]) + abs(b[2] - b[1]) + abs(b[3] - b[1]); // 最小步数使4位相同
                if((n & 1)&&i == (n + 1)/2) // 如果两行相同的处理
                    res /= 2;
                if((m & 1)&&j == (m + 1)/2) // 列是相同的处理
                    res /= 2;
                ans += res;
            }
        }
        cout<<ans<<endl;
    }
    
    return 0;
}

C. Bargain

题意

给定一个很大的数,可以从中删除一段连续的部分(非空),这样就能使这个数有很多不同的可能,求这些可能的不同取值

思路

我们可以枚举这个数每一位的所有可能的和即在这个数的前面删除,或后面删除。
这个数位 a1a2a3···an-1an
假设他在i位
如果在前面删除
对于从他前面的第一位删除有 i - 1 种
对于从他前面的第两位删除有 i - 2 种
··········
对于从他前面的第i - 1位删除有 1 种
即有 i * (i - 1) / 2 中
结果为 ai * 10n-i * i * (i - 1)/2
如果在后面删除,
假设他后面有k为
如果这个数在最后一位,只能把后面的k位都删除,1种可能,且为 ai
如果这个数在倒数第二位,可以把连续的k - 1位删除,2种可能 且为 ai * 10
如果这个数在倒数第三位,可以把连续的k - 2位删除,3种可能 且为 ai * 102
这样我们就能发现所有的规律

代码

#include
#include
using namespace std;
const int N = 1e5+10,mod = 1e9+7;
#define int long long
char s[N];
int f[N];
 
signed main(){
     
    scanf("%s",s + 1);
    int n = strlen(s + 1);
    int ans = 0,p = 1;
    int now = 0; // 表示前面的所有可能
    for(int i = n;i >= 1;i--){
     
        int v = s[i] - '0';
        int cur = (now + (i * (i - 1) / 2) % mod * p % mod)%mod; // 后面加上前面的所有可能
        ans = (ans + cur * v) % mod; // 乘上这个数
        now = (now + p * (n - i + 1)%mod)%mod;  // 对于下一位多了这个数字在后面有n - i + 1位的情况
        p = (p * 10) % mod;
    }
    cout<<ans<<endl;
    return 0;
}

感觉有点跳跃性,多看看还是可以理解的

D. Returning Home

题意

给定一个n * n 的地图,给定一个起点和一个终点,求起点到终点需要多少最短时间,走一步时间为1,给了m个神奇的点,如果在x坐标或y坐标在等于神奇的点的x坐标或y坐标,那么就可以瞬移到这个神奇的点

思路

我们可以把起点也可以看做神奇的点,因为没有必要走两次起点。我们很容易想到最后走到终点的点必然是这些神奇的点中的一个,一个最暴力的想法就是给这些神奇的点建边,求出到每个点的最短距离,但是这样就要给每个点建立 n - 1 条边即 n * (n - 1) 条边,无论在时间还是空间都是不允许,这就需要我们优化一下边,走到一个点无非是从x方向或y方向,如果在x方向上到达也可以想象成先到比他 x小的最大的那个点或大于x的最小的那个点,在走在这个点,因为他的特性,直接走和这样的时间是等价的,所以我们就可以这样直接建立在x方向上相邻的点和在y方向相邻的点之间的边(只需要建立 4 * n 条边),然后通过dijkstra直接算出到这些点距离。

代码

#include
#include
#include
#include
using namespace std;
const int N = 1e5+10,M = 4 * N;
#define x first
#define y second
typedef pair<int ,int > PII;
int h[N],e[M],ne[M],w[M],idx;
bool st[N];
int d[N],id[N];
PII a[N];
PII ed;
bool cmp1(int x,int y){
     
    return a[x].x < a[y].x;
}
bool cmp2(int x,int y){
     
    return a[x].y < a[y].y;
}
void add(int a,int b,int c){
     
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
void dijkstra(){
      
    memset(d,0x3f,sizeof d);
    d[0] = 0;
    priority_queue<PII ,vector<PII> ,greater<PII>>hp;
    hp.push({
     0,0});
    while(hp.size()){
     
        auto t = hp.top();
        hp.pop();
        int ver = t.y,dist = t.x;
        if(st[ver]) continue;
        st[ver] = true;
        for(int i = h[ver];i!=-1;i = ne[i]){
     
            int j = e[i];
            if(d[j] > dist + w[i]){
     
                d[j] =  dist + w[i];
                hp.push({
     d[j],j});
            }
        }
    }
}
int main(){
     
    ios::sync_with_stdio(false);
    memset(h,-1,sizeof h);
    int n,m;
    cin>>n>>m;
    cin>>a[0].x>>a[0].y;
    cin>>ed.x>>ed.y;
    id[0] = 0;
    for(int i = 1;i <= m;i++){
     
        cin>>a[i].x>>a[i].y;
        id[i] = i;
    }
    sort(id,id + m + 1,cmp1); // x方向排序
    for(int i = 1;i<=m;i++){
      // x方向建边
        int t = a[id[i]].x - a[id[i - 1]].x;
        add(id[i],id[i - 1],t);
        add(id[i - 1],id[i],t);
    }
    sort(id,id + m + 1,cmp2); // y方向排序
    for(int i = 1;i<=m;i++){
      // y方向建边
        int t = a[id[i]].y - a[id[i - 1]].y;
        add(id[i],id[i - 1],t);
        add(id[i - 1],id[i],t);
    }
    dijkstra();
    int ans = 2e9;
 
    for(int i = 0;i<=m;i++){
     
        ans = min(ans,d[i] + abs(ed.x - a[i].x) + abs(ed.y - a[i].y)); // 从神奇的带你到终点
    }
    cout<<ans<<endl;
    return 0;
}

你可能感兴趣的:(codeforces,div2,算法)