2017 Shenyang Railway Station (Revisiting Classics)

Posted by HA7E on Mon, 07 Feb 2022 20:42:55 +0100

Introduction

In the bronze medal area, but there is still a certain distance from the silver medal. There is not much time left. We need to focus more and consolidate more

Knowledge points involved

Thinking, search, large number operation

subject

F

Define a triangle whose side lengths are integers t − 1 , t , t + 1 t-1,t,t+1 T − 1,t,t+1 and the area of the triangle is an integer, give an integer n n n. Find one just larger than n n Integer of n t t t. Make the triangle conform to the definition

Idea: to find the law, first calculate the triangle area according to the given data and bring it into Helen's formula S = 3 × t 2 ( t 2 − 4 ) / 16 S=\sqrt{3×t^2(t^2-4)/16} S=3×t2(t2−4)/16 , since the area is an integer, the equation can be obtained t 4 − 4 t 2 − 48 S 2 = 0 t^4-4t^2-48S^2=0 t4 − 4t2 − 48S2=0, which can be brought in by typing the table t t t calculation S S S. If S S If S is an integer t t t is the solution, and the general term formula can be obtained by typing the table t i = 4 t i − 1 − t i − 2 t_i=4t_{i-1}-t_{i-2} ti = 4ti − 1 − ti − 2, we can see that the data basically increases exponentially, so 1 0 30 10^{30} There are not many effective solutions in the range of 1030. It can be directly processed on-line with large input and output, and can be recursive to the first t greater than n

code

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
__int128 a[1000];
void scan(__int128 &x)//input
{
	x=0;int f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	x*=f;
}
void print(__int128 x)//output
{
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
void solve()
{
    __int128 n,t1,t2;
    scan(n);
    t1=2;
    for(t2 = 4;t2<n;t2=t2*4-t1)
    {
        t1=t2;
    }
    print(t2);
    printf("\n");
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
    return 0;
}

G

Main idea of the title: give a number sequence composed of 0-9 with a length of N, subscript 0 ~ n-1. You can only go from the point with subscript i to the point with subscript (i*i+1)%n. select a starting point to go n times, record the numbers each time, and find the maximum dictionary sequence of number structure

Idea: if the overall structure is the largest, each bit should be the largest as far as possible, and each bit must be searched. Store the subscripts of the largest number in the sequence uniformly for search. Here, if you directly search DFS, it will timeout. In order to construct strings and prune faster, BFS is more appropriate
In order to select the minimum number of positions in the front of the stack according to the current construction scheme, and the maximum number of positions can be selected according to the minimum number of positions in the front of each construction step, If two points reach the same point after the same number of steps, the subsequent state is the same. This scheme only needs to be calculated once. See the code for details

code

#include <bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=2e5+5;
int T,val[maxn],n,x,ans[maxn],nt[maxn];
char s[maxn];
struct node {
    int step,pos;
    bool operator<(const node&a)const {
        if(step==a.step&&nt[pos]==nt[a.pos])return pos<a.pos;
        //The number of steps is equal, the next step is equal, and the position is judged
        if(step==a.step)return nt[pos]<nt[a.pos];
        //If the number of steps is equal, judge the next step
        return step>a.step;
        //Judgment steps
    }
};
signed main() {
    scanf("%lld",&T);
    for(int k=1; k<=T; k++) {
        scanf("%lld%s",&n,s);
        int mx=0;
        for(int i=0; i<n; i++) {
            val[i]=s[i]-'0';
            mx=max(mx,val[i]);//Get maximum
            ans[i]=-1;//initialization
        }
        for(int i=0; i<n; i++)
            nt[i]=val[(i*i+1)%n];//Initialize next step
        ans[n]=-1,ans[1]=mx;
        int pre=-1;
        priority_queue<node>q;
        for(int i=0; i<n; i++)
            if(val[i]==mx)q.push(node{1,i});//Find the position with the largest starting number for BFS
        while(!q.empty()) {
            node t=q.top();//The position with the minimum number of steps and the maximum current position value must be selected each time
            q.pop();
            int pos=(t.pos*t.pos+1)%n,step=t.step+1;
            //Position and steps of the next jump
            if(ans[step]==-1) {//The first one jumps to step
                q.push(node{step,pos});
                ans[step]=val[pos];//Update the string constructed in this step
                pre=pos;//Record last position
            } else if(val[pos]==ans[step]) {//If there are other positions, jump to the same point
                if(pos!=pre) {//Judge whether it is the same point. If it is not, it indicates that there may be other schemes
                    q.push(node{step,pos});
                    pre=pos;
                }
            }
            if(ans[n]!=-1)break;//The last position has been constructed
        }
        printf("Case #%lld: ",k);
        for(int i=1; i<=n; i++)printf("%lld",ans[i]);
        putchar('\n');
    }
    return 0;
}

I

Calculate the four maximum 2 62 2^{62} Addition of positive integers of 262

Idea: calculate directly with int128

code

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
void scan(__int128 &x)//input
{
	x=0;int f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	x*=f;
}
void print(__int128 x)//output
{
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
void solve()
{
    __int128 a,b,c,d,res;
    scan(a);
    scan(b);
    scan(c);
    scan(d);
    res = a+b+c+d;
    print(res);
    printf("\n");
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
    return 0;
}

K

Main idea of the title: omitted

Idea: with greedy thinking, try to insert the whole large interval on the right with the left endpoint as the benchmark and the whole large interval on the left with the right endpoint as the benchmark. The best result is all the spaces in the interval. Calculate the number of spaces and the extreme value respectively

code

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int a[505];
void solve()
{
    int n,res=0;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",a+i);
    }
    res = max(res,a[n-1]-a[1]-1-n+3);
    res=max(res,a[n]-a[2]-1-n+3);
    printf("%d\n",res);
}

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
    return 0;
}

L

The main idea of the topic: a rootless tree, colors the nodes with k colors, connects the node paths of each color, and obtains the edge set. Each color has an edge set. Find the maximum intersection of the edge set

Idea: the largest intersection of edge sets means that there are more public edges. For an edge, if it is a public edge, there must be more than or equal to k nodes on its left and right. Even if there are multiple public edges, the coloring scheme can always be found, so that the coloring of these public edges can be greater than or equal to k on both left and right. Just find such edges directly

code

#include <bits/sdc++.h>
#define int long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=2e5+10;
int Size[maxn],T,k,head[maxn],n,cnt;
struct node {
    int from,to,next;
} e[maxn<<1];
void Add(int from,int to) {
    e[++cnt].to=to;
    e[cnt].from=from;
    e[cnt].next=head[from];
    head[from]=cnt;
}
void DFS(int u,int f) {//Statistical subtree size
    Size[u]=1;
    for(int i=head[u]; ~i; i=e[i].next) {
        int v=e[i].to;
        if(v==f)continue;
        DFS(v,u);
        Size[u]+=Size[v];
    }
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >>T;
    while(T--) {
        int res=0;
        cin >>n>>k;
        memset(head,-1,sizeof(int)*(n+1));
        memset(Size,0,sizeof(int)*(n+1));
        for(int i=1; i<n; i++) {
            int u,v;
            cin >>u>>v;
            Add(u,v);
            Add(v,u);
        }
        DFS(1,0);
        for(int i=1; i<=n; i++)
            if(Size[i]>=k&&n-Size[i]>=k)res++;
        /*Here is a little trick, because it is carried out according to the sequence number, so it will not appear
        In the case of repeated calculation, for example, if the 1-2 edge is feasible, it will not be
        When calculating 1, the count can be verified by drawing. If both sides are feasible, but
        If they share one point, one point must be greater than the common point and the other less than the common point,
        It can still be calculated twice, and the judgment conditions in the code only deal with one edge at a time
        */
        cout <<res<<endl;
    }
    return 0;
}

M

General idea: n × N map, some grids have obstacles and can't walk (less than 1000), and the x coordinate is [ 0 , n − 1 ] [0,n-1] [0,n − 1], y coordinate is [ 0 , n − 1 ] [0,n-1] [0,n − 1], the starting point is (0,0), and you can only go to the adjacent grid each time. After a long enough time, the coordinates of the end point are satisfied x + y ≥ n − 1 x+y\ge n-1 Probability of x+y ≥ n − 1

Idea: since it is a long enough time, in theory, all points can be reached except the obstacle point. Whether each point can be reached and the probability of reaching depends on how many points can reach it. Therefore, each point can be weighted. The size of the weight indicates that several points of the current point can reach it. Then, for a point, set the weight of the point as v v v. The probability of reaching this point is v i ∑ i = 1 n v i \frac{v_i}{\sum_{i=1}^nv_i} Σ i=1n vi VI, therefore, the probability of reaching the given area of the subject is the sum of the point weights in the corresponding area divided by the sum of the total point weights. Because there are too many points, the positive and difficult are the opposite. You can first calculate the total numerator denominator, and then subtract the contribution of the obstacle. Pay attention to the special judgment

code

#include <bits/stdc++.h>
#define int long long
using namespace std;
int t,n,k,Next[4][2]= {0,1,1,0,-1,0,0,-1};
map<int,bool>Umap;
int gcd(int a,int b) {
    if(b==0)return a;//Note that special judgment b is 0
    int res=1;
    while(res) {
        res=a%b;
        a=b;
        b=res;
    }
    return a;
}
void solve() {
    int mole=3*3+2*4*(n-2)+5*(n-1)*(n-2)/2;//Computational molecule
    int deno=3*4+4*4*(n-2)+5*(n-2)*(n-2);//
    for(auto i=Umap.begin(); i!=Umap.end(); i++) {
        if(!i->second)continue;//Remove points that are not obstacles
        int y=i->first%n,x=(i->first-y)/n,val=5;//Obtain the coordinates and set the initial value
        if(x==0||x==n-1)val--;
        if(y==0||y==n-1)val--;
        deno-=val;//Minus contribution
        if(x+y>=n-1)mole-=val;//ditto
        for(int j=0; j<4; j++) {
            int _x=x+Next[j][0],_y=y+Next[j][1],id=_x*n+_y;//Traverse adjacent contact
            if(_x<0||_x>n-1||_y<0||_y>n-1||Umap[id])continue;//If you cross a line or an obstacle
            deno--;//Yes, the contribution is reduced
            if(_x+_y>=n-1)mole--;//It's the end, and the contribution decreases
        }
    }
    int _gcd=gcd(mole,deno);
    mole/=_gcd,deno/=_gcd;
    cout <<mole<<"/"<<deno;
    Umap.clear();
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >>t;
    for(int i=1; i<=t; i++) {
        cin >>n>>k;
        cout <<"Case #"<<i<<": ";
        for(int j=1; j<=k; j++) {//sign
            int x,y;
            cin >>x>>y;
            Umap[x*n+y]=1;
        }
        if(n==1) {//Special judgment
            if(k==1)cout <<0;
            else cout <<1;
        } else solve();
        cout <<endl;
    }
    return 0;
}

reference

  1. HDU - 6229 Wandering Robots
  2. 2017icpc Shenyang G Infinite Fraction Path BFS + pruning

Topics: Algorithm