2018 Multi-University Training Contest 5-Everything Has Changed-Beautiful Now-Glad You Came

2018 Multi-University Training Contest 5__全部题解+标程:

https://blog.csdn.net/scar_halo/article/details/81458001

1005 Everything Has Changed

Edward is a worker for Aluminum Cyclic Machinery. His work is operating mechanical arms to cut out designed models. Here is a brief introduction of his work.
Assume the operating plane as a two-dimensional coordinate system. At first, there is a disc with center coordinates (0,0) and radius R. Then, m mechanical arms will cut and erase everything within its area of influence simultaneously, the i-th area of which is a circle with center coordinates (xi,yi) and radius ri (i=1,2,⋯,m). In order to obtain considerable models, it is guaranteed that every two cutting areas have no intersection and no cutting area contains the whole disc.
Your task is to determine the perimeter of the remaining area of the disc excluding internal perimeter.
Here is an illustration of the sample, in which the red curve is counted but the green curve is not.

 

Input

The first line contains one integer T, indicating the number of test cases.
The following lines describe all the test cases. For each test case:
The first line contains two integers m and R.
The i-th line of the following m lines contains three integers xi,yi and ri, indicating a cutting area.
1≤T≤1000, 1≤m≤100, −1000≤xi,yi≤1000, 1≤R,ri≤1000 (i=1,2,⋯,m).

Output

For each test case, print the perimeter of the remaining area in one line. Your answer is considered correct if its absolute or relative error does not exceed 10−6.
Formally, let your answer be a and the jury's answer be b. Your answer is considered correct if |a−b|max(1,|b|)≤10−6.

Sample Input

1

4 10

6 3 5

10 -4 3

-2 -4 4

0 9 1

题意:在一个坐标圆心(0,0)半径为R的圆上切下去m个圆,问剩下的圆的部分外圈的周长

题解:判断两个圆的位置,然后利用余弦定理求圆心角,加减弧长就可以

代码:

#include<iostream>
    #include<stdio.h>
    #include<math.h>
    #define PI acos(-1.0)
    using namespace std;
    int main()
    {
        int t;
        scanf("%d",&t);
        double a1,b1,r1,a2,b2,r2,d;
        double A1,A2,s1,s2,s;
        while(t--)
        {
            double ans=0;
            a1=b1=0;
            int hh;
            scanf("%d %lf",&hh,&r1);
            ans=2*PI*r1;
            for(int i=1;i<=hh;i++)
            {
                scanf("%lf%lf%lf",&a2,&b2,&r2);
                d=sqrt((a2)*(a2)+(b2)*(b2));
                if(d>=r1+r2)
                {
                 ans+=0;
                 continue;
                }
                else
                if(d==fabs(r1-r2))//内切
                {
                  ans+=PI*r2*2;
                  continue;
                }
                else
                if(d<r1+r2&&d>fabs(r1-r2))//两个圆相交的情况
                  {
                    A1=2*acos((d*d+r1*r1-r2*r2)/(2*d*r1));
                    A2=2*acos((d*d+r2*r2-r1*r1)/(2*d*r2));
                    ans-=A1*r1;
                    ans+=A2*r2;
                    continue;
                  }
              }
            printf("%.20lf\n",ans);
        }
        return 0;
    }

 

1002 Beautiful Now

Problem Description

Anton has a positive integer n, however, it quite looks like a mess, so he wants to make it beautiful after k swaps of digits.
Let the decimal representation of n as (x1x2⋯xm)10 satisfying that 1≤x1≤9, 0≤xi≤9 (2≤i≤m), which means n=∑mi=1xi10m−i. In each swap, Anton can select two digits xi and xj (1≤i≤j≤m) and then swap them if the integer after this swap has no leading zero.
Could you please tell him the minimum integer and the maximum integer he can obtain after k swaps?

Input

The first line contains one integer T, indicating the number of test cases.
Each of the following T lines describes a test case and contains two space-separated integers n and k.
1≤T≤100, 1≤n,k≤109.

Output

For each test case, print in one line the minimum integer and the maximum integer which are separated by one space.

Sample Input

5

12 1

213 2

998244353 1

998244353 2

998244353 3

Sample output

12 21

123 321

298944353 998544323

238944359 998544332

233944859 998544332

题目:
给你一个字符串,交换最多k次,找出里面最小的字符串和最大的字符串
代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#include <sstream>
#define inf 800000000000
#define ll long long
#define mod 1000000007
using namespace std;
string maxs,mins;
int n;
/**求最小深搜**/
void dfs1(int now,int k,string st) //顶指针,交换剩余次数,当前字符串
{
    int i,minn;
    if(k==0||now==n)
    {
        if(st<mins)
        {
            mins=st;
        }
        return;
    }
    if(now==0) //第一位,此时不能有前导零
    {
        minn=now;
        for(i=now+1;i<n;i++)
        {
            if(st[i]!='0'&&st[i]<=st[minn]&&st[i]!=st[now])
            {
                minn=i;
            }
        }
        if(minn!=now)
        {
            for(i=now+1;i<n;i++)
            {
                if(st[i]==st[minn])
                {
                    string s=st;
                    swap(s[now],s[i]);
                    dfs1(now+1,k-1,s); //有交换情况,交换
                }
            }
        }
        else
            dfs1(now+1,k,st);  //无交换情况,不交换,顶指针进一位
    }
    else// 非第一位
    {
        minn=now;
        for(i=now+1;i<n;i++)
        {
            if(st[i]<=st[minn]&&st[i]!=st[now])
            {
                minn=i;
            }
        }
        if(minn!=now)
        {
            for(i=now+1;i<n;i++)
            {
                if(st[i]==st[minn])
                {
                    string s=st;
                    swap(s[now],s[i]);
                    dfs1(now+1,k-1,s);
                }
            }
        }
        else
            dfs1(now+1,k,st);
    }
    return;
}
/**求最大深搜,和上面一样**/
void dfs2(int now,int k,string st)
{
    int i,maxn;
    if(k==0||now==n)
    {
        if(st>maxs)
        {
            maxs=st;
        }
        return;
    }
    if(now==0)
    {
        maxn=now;
        for(i=now+1;i<n;i++)
        {
            if(st[i]!='0'&&st[i]>=st[maxn]&&st[i]!=st[now])
            {
                maxn=i;
            }
        }
        if(maxn!=now)
        {
            for(i=now+1;i<n;i++)
            {
                if(st[i]==st[maxn])
                {
                    string s=st;
                    swap(s[now],s[i]);
                    dfs2(now+1,k-1,s);
                }
            }
        }
        else
            dfs2(now+1,k,st);
    }
    else
    {
        maxn=now;
        for(i=now+1;i<n;i++)
        {
            if(st[i]>=st[maxn]&&st[i]!=st[now])
            {
                maxn=i;
            }
        }
        if(maxn!=now)
        {
            for(i=now+1;i<n;i++)
            {
                if(st[i]==st[maxn])
                {
                    string s=st;
                    swap(s[now],s[i]);
                    dfs2(now+1,k-1,s);
                }
            }
        }
        else
            dfs2(now+1,k,st);
    }
    return;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int k;
        string s;
        cin>>s;
        scanf("%d",&k);
        mins=s;
        n=s.length();
        dfs1(0,k,s);
        cout<<mins<<" ";
        maxs=s;
        dfs2(0,k,s);
        cout<<maxs<<endl;
    }
}

 

1007Glad You Came

Steve has an integer array a of length n (1-based). He assigned all the elements as zero at the beginning. After that, he made m operations, each of which is to update an interval of a with some value. You need to figure out ⨁ni=1(i⋅ai) after all his operations are finished, where ⨁ means the bitwise exclusive-OR operator.
In order to avoid huge input data, these operations are encrypted through some particular approach.
There are three unsigned 32-bit integers X,Y and Z which have initial values given by the input. A random number generator function is described as following, where ∧ means the bitwise exclusive-OR operator, << means the bitwise left shift operator and >> means the bitwise right shift operator. Note that function would change the values of X,Y and Z after calling.


Let the i-th result value of calling the above function as fi (i=1,2,⋯,3m). The i-th operation of Steve is to update aj as vi if aj<vi (j=li,li+1,⋯,ri), where

⎧⎩⎨⎪⎪lirivi=min((f3i−2modn)+1,(f3i−1modn)+1)=max((f3i−2modn)+1,(f3i−1modn)+1)=f3imod230(i=1,2,⋯,m).

 

Input

The first line contains one integer T, indicating the number of test cases.
Each of the following T lines describes a test case and contains five space-separated integers n,m,X,Y and Z.
1≤T≤100, 1≤n≤105, 1≤m≤5⋅106, 0≤X,Y,Z<230.
It is guaranteed that the sum of n in all the test cases does not exceed 106 and the sum of m in all the test cases does not exceed 5⋅107.

Output

For each test case, output the answer in one line.

Sample Input

4

1 10 100 1000 10000

10 100 1000 10000 100000

100 1000 10000 100000 1000000

1000 10000 100000 1000000 10000000

Sample Output

1031463378

1446334207

351511856

47320301347

Hint

In the first sample, a = [1031463378] after all the operations.

In the second sample, a = [1036205629, 1064909195, 1044643689, 1062944339, 1062944339, 1062944339, 1062944339, 1057472915, 1057472915, 1030626924] after all the operations.

题意:更新区间里面比当前值小的数; 
做法:典型的线段树区间,不过用线段树需要剪枝,毕竟线段树比较慢。 
还有一个做法是用st,rmq,只需要把查询改成更新,更新改成查询就好了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 1e5+7;
int st[N][20];
int lg[N];
unsigned int x,y,z;
void init(){
    lg[1] = 0;
    int now = 2;
    for(int i = 2;i < N;i ++){
        lg[i] = lg[i-1];
        if(i > now) lg[i]++,now*=2;
    }
}
unsigned int get(){
    x = x^(x<<11);
    x = x^(x>>4);
    x = x^(x<<5);
    x = x^(x>>14);
    unsigned int w = x^y^z;
    x = y;
    y = z;
    z = w;
    return z;
}


void update(int l,int r,int x){
    int l2 = lg[r-l+1];
    st[l][l2] = max(st[l][l2],x);
    st[r-(1<<l2)+1][l2] = max(st[r-(1<<l2)+1][l2],x);
}
long long get(int n){
    int l2 = lg[n];
    for(int i = l2;i >= 1;i --){
        for(int j = 1;j <= n;j ++){
            if(j+(1<<i)> n+1) break;
            st[j][i-1] = max(st[j][i-1],st[j][i]);
            st[j+(1<<(i-1))][i-1] = max(st[j+(1<<(i-1))][i-1],st[j][i]);
        }
    }
    long long ret = 0;
    for(int i = 1;i <= n;i ++){
        ret ^= 1LL*i*st[i][0];
    }
    return ret;
}
void set0(int n){
    int l2 = lg[n];
    for(int i = 0;i <= l2;i ++){
        for(int j = 1;j <= n;j ++) st[j][i] = 0;
    }
}


int main(){
    init();
    int T;
    cin >> T;
    while(T--){
        //memset(st,0,sizeof(st));

        int n,m;
        scanf("%d %d",&n,&m);
        set0(n);
        scanf("%u %u %u",&x,&y,&z);
        for(int i = 1;i <= m;i ++){
            int l = get()%n+1,r = get()%n+1,v =get()%(1<<30);
            if(l > r) swap(l,r);
            update(l,r,v);
        }
        printf("%lld\n",get(n));
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值