Codeforces Round #675 (Div. 2) AD problem solution

Codeforces Round #675 (Div. 2) AD question solution
contest link: https://codeforces.com/contest/1422

Question A

The question means that given three sides of a quadrilateral, you can output an integer instead of being able to form a quadrilateral.

Similar to the triangle theorem, the sum of the three sides that need to meet the minimum length needs to be greater than the largest one.
The construction method I chose here is to subtract the other two sides from the largest side (and 0 to take a max) and add 1.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

int32_t main()
{
    
    
    IOS;
    int t;
    cin>>t;
    while(t--)
    {
    
    
        ll a,b,c;
        cin>>a>>b>>c;
        if(a>b) swap(a,b);
        if(b>c) swap(b,c);
        cout<<max(0ll,c-a-b)+1<<endl;
    }
}

Question B
Simple conclusion, detailed processing.

The title means given a n × \times× n matrix, you can +1 or -1 to a certain number in each operation, and ask how many operations you need at least to make each column of the entire matrix symmetrical, and each row is also symmetrical.

Here, let’s observe first, we use the center of the matrix as the origin, and establish the coordinate system horizontally and vertically. We will find that the points on the x and y axes in the matrix only need to be consistent with another number, not on the coordinate axis. All points need to be consistent with the other three numbers.

The number of operations to keep two numbers the same is simple, it is the absolute value of the difference between the two numbers.
If the four numbers are consistent, we can use the assumption that the value of the final number is in which range to reach a conclusion.
Suppose the four numbers are sorted from small to large as a, b, c, d. We assume that the last constructed value falls on the right side of c, then we can make this value -1. In this case, the three numbers a, b, and c are operated once less, and d is operated once more, and the total number of operations is -2 , Will be better.
In the same way, it can be deduced that the final constructed value on the left side of b is not optimal either.
Therefore, the final value we constructed is in the closed interval from b to c, and the number of operations is the same. So directly subtracting the absolute value of four numbers from c is the minimum number of operations.

Then it was achieved.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;

ll num[107][107];

int32_t main()
{
    
    
    IOS;
    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>>num[i][j];
        ll ans=0;
        for(int i=1;i<=n/2;i++)//除了奇数行的中间行外,所有位置都有对应三个另外的位置要保持相同
        {
    
    
            for(int j=1;j<=m/2;j++)
            {
    
    
                vector<ll>temp;
                temp.push_back(num[i][j]);
                temp.push_back(num[i][m-j+1]);//同一行的另一个数
                temp.push_back(num[n-i+1][j]);//同一列的另一个数
                temp.push_back(num[n-i+1][m-j+1]);//关于矩阵中心对称的另一个数
                sort(temp.begin(),temp.end());
                for(auto &x:temp) ans+=abs(x-temp[2]);
            }
            if(m&1) ans+=abs(num[i][m/2+1]-num[n-i+1][m/2+1]);//中间列是特殊情况
        }
        if(n&1)//奇数行的中间那一行额外处理,此时每个位置需要保持相同的数只有另外一个
        {
    
    
            for(int j=1;j<=m/2;j++) ans+=abs(num[n/2+1][j]-num[n/2+1][m-j+1]);
        }
        cout<<ans<<endl;
    }
}

C title
dp

The question means that given a number with a maximum length of 1e5 level, you can delete a continuous segment of numbers with a length other than 0, and join the remaining numbers to form a new number.
You need to output the sum of all the numbers from the deletion scheme.

It is a linear dp that is easier to see. For the specific transfer equation, please refer to the code and comments.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxn=1e5+7;
const ll mod=1e9+7;

string s;

struct Node
{
    
    
    ll data,cas;//data记录值总共为多少,cas为有多少组情况
};

Node dp[maxn][3];//方便理解起见,这里每个下标对应三种状态
//dp[i][0]代表用前i个数字在已经删除了一段区间并且这个区间的最后一个位置是下标i的情况下,构成的所有数值和,以及对应有多少组情况
//dp[i][1]代表用前i个数字在已经删除了一段区间并且这个区间的最后一个位置不是下标i的情况下,构成的所有数值和,以及对应有多少组情况
//dp[i][2]代表用前i个数字未删除区间的情况下,构成的所有数值和,以及对应有多少组情况(这里一直是1)

int32_t main()
{
    
    
    IOS;
    cin>>s;
    dp[0][2].cas=1;
    for(int i=0;i<s.size();i++)
    {
    
    
        dp[i+1][0].cas=(dp[i][0].cas+dp[i][2].cas)%mod;//删除当前位置,由于只能删除一段连续的区间,因此不能从dp[i][1]转移过来
        dp[i+1][0].data=(dp[i][0].data+dp[i][2].data)%mod;

        dp[i+1][1].cas=(dp[i][0].cas+dp[i][1].cas)%mod;//保留当前位置,并且之前已经有删除过,因此从dp[i][0]和[1]转移过来
        dp[i+1][1].data=((dp[i][0].data+dp[i][1].data)%mod*10%mod+dp[i+1][1].cas*(s[i]-'0')%mod)%mod;

        dp[i+1][2].cas=dp[i][2].cas;
        dp[i+1][2].data=(dp[i][2].data*10+s[i]-'0')%mod;
    }
    cout<<(dp[s.size()][0].data+dp[s.size()][1].data)%mod<<endl;
}

Question D
Thinking, optimization of conclusions, shortest path

The question means that given the coordinates of the start and end points on a two-dimensional plane, you can only move a distance of 1 up, down, left, and right each time you move.
But there are m special nodes on this plane. When your position is the same as the abscissa or ordinate of this node, you can directly reach the position of this node without spending any time. Ask how many times to move from the start point to the end point at least (excluding the movement of teleporting to a special node).

It’s easy to think of here. Taking the starting point and the end point and m special points as the nodes of the graph becomes the shortest path problem, where the distance between the start point and the end point is the absolute value of the abscissa difference, and there are special points. As the edge of the end point, the smaller value of the difference between the abscissa and the ordinate is used as the distance. However, if the composition is like this, it is a complete graph with m+2 nodes, and the number of edges (m+2) 2 will be the shortest path.
We noticed that the one-way edges from the starting point to m special points, and the one-way edges from the starting point and m special points to the end point must be added to the graph.
However, the m 2 special edges between m special points can still be optimized, and not all need to be added.
Here we must first push a small conclusion, for two points a[x1,y1],b[x2,y2], x1<x2,y1<y2, if there is a third point c[x3,y3], satisfy x1< =x3<=x3 or y1<=y2<=y3.
Since from point a to point b, it is necessary to go from point a through the x direction (horizontal) or y direction (vertical) to a position that can be directly moved to b. In this process, it will inevitably pass through a certain point with the same horizontal and vertical coordinates of point c, teleport to point c and then follow the original path direction. The number of moves required will not change. That is to say, the path between a and b can be composed of two paths a to c and c to b.
That is, the distance between any two special points can be represented by the edge of the point between the two special points in the x direction or the y direction. After using this conclusion to continuously divide the large edges, they are finally transformed into edges between two adjacent points in the x and y directions.
As a result, m 2 edges are compressed into 2m-2 edges. At this time, the shortest path algorithm mlogn can be run in time.

#include<bits/stdc++.h>
#define ll long long
#define llINF 9223372036854775807
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
using namespace std;
const ll maxm=1e5+7;

struct Edge
{
    
    
    ll to,next,dis;
}edge[maxm<<3];

ll head[maxm],tot;
ll n,m;

void init()
{
    
    
    for(ll i=0;i<=m+1;i++) head[i]=-1;
    tot=0;
}

void add(ll u,ll v,ll w)
{
    
    
    edge[tot].to=v;
    edge[tot].next=head[u];
    edge[tot].dis=w;
    head[u]=tot++;
}

ll dis[maxm];

struct Node
{
    
    
    ll pos,val;
    Node(ll pos,ll val):pos(pos),val(val){
    
    }
    friend bool operator < (Node a,Node b)
    {
    
    
        return a.val>b.val;
    }
};

ll Dijstra()
{
    
    
    for(ll i=0;i<=m+1;i++) dis[i]=llINF;
    dis[0]=0;
    priority_queue<Node>Q;
    Q.push(Node(0,0));
    while(Q.size())
    {
    
    
        Node now=Q.top();
        Q.pop();
        if(now.val>dis[now.pos]) continue;
        for(ll i=head[now.pos];i!=-1;i=edge[i].next)
        {
    
    
            ll to=edge[i].to;
            if(dis[to]>edge[i].dis+now.val)
            {
    
    
                dis[to]=edge[i].dis+now.val;
                Q.push(Node(to,dis[to]));
            }
        }
    }
    return dis[m+1];
}

struct Point
{
    
    
    ll x,y,tar;
}point[maxm];

bool cmp1(Point a,Point b){
    
    return a.x<b.x;}
bool cmp2(Point a,Point b){
    
    return a.y<b.y;}

int32_t main()
{
    
    
    IOS;
    cin>>n>>m;
    init();
    cin>>point[0].x>>point[0].y>>point[m+1].x>>point[m+1].y;//起点下标0,终点下标m+1
    for(ll i=1;i<=m;i++) {
    
    cin>>point[i].x>>point[i].y;point[i].tar=i;}
    for(ll i=1;i<=m;i++) add(0,i,min(abs(point[i].x-point[0].x),abs(point[i].y-point[0].y)));//起点到m个特殊点的边加进图中
    for(ll i=0;i<=m;i++) add(i,m+1,abs(point[m+1].x-point[i].x)+abs(point[m+1].y-point[i].y));//起点和m个特殊点,与终点的边加进图中
    //以上均可以直接设置为单向边
    //之后还需要加的就是m个特殊点之间的边了
    sort(point+1,point+m+1,cmp1);//按照x从小到大排序后,相邻特殊点之间建立双向边
    for(ll i=1;i<m;i++)
    {
    
    
        ll dis=min(abs(point[i].x-point[i+1].x),abs(point[i].y-point[i+1].y));
        add(point[i].tar,point[i+1].tar,dis);
        add(point[i+1].tar,point[i].tar,dis);
    }
    sort(point+1,point+m+1,cmp2);//按照y从小到大排序后,相邻特殊点之间建立双向边
    for(ll i=1;i<m;i++)
    {
    
    
        ll dis=min(abs(point[i].x-point[i+1].x),abs(point[i].y-point[i+1].y));
        add(point[i].tar,point[i+1].tar,dis);
        add(point[i+1].tar,point[i].tar,dis);
    }
    cout<<Dijstra()<<endl;//跑个最短路完事了
}

Guess you like

Origin blog.csdn.net/StandNotAlone/article/details/109048820