ZJNU-12-06 组队赛

A-Simple Calculator

题意:

给了两个数x,y。现在给你两个按钮,按钮A将x+1,按钮B将x的符号翻转,问最少要多少次操作,使x=y。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
int x,y;
int main()
{
   
    scanf("%d%d",&x,&y);
    if(x>0&&y>0)
    {
   
        if(x>y)
            printf("%d",x-y+2);
        else
            printf("%d",y-x);
    }
    else if(x>0&&y<0)
    {
   
        if(x>-y)
            printf("%d",1+x+y);
        else
            printf("%d",1-x-y);
    }
    else if(x<0&&y<0)
    {
   
        if(x<y)
            printf("%d",y-x);
        else
            printf("%d",2+x-y);
    }
    else if(x<0&&y>0)
    {
   
        if(-x>y)
            printf("%d",1-x-y);
        else
            printf("%d",1+x+y);
    }
    else if(x==0)
    {
   
        if(y>=0)
            printf("%d",y);
        else
            printf("%d",1-y);
    }
    else
    {
   
        if(x>0)
            printf("%d",1+x);
        else
            printf("%d",-x);
    }
    return 0;
}

B-Contiguous Repainting

题意:

给了你一个长度为n的数组,每次你能将连续k个数涂成黑色或白色,可覆盖,可以填任意多次,问黑色方块上的数加起来最多为多少。

solution:

根据题意分析,可以知道可以先取出k个数特判,其余的只要贪心的取正数即可。因此先将正数的和求出来,然后每k个数判断一下加上负数和或者去掉正数和哪种情况更优,取个max。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
int n,k;
int a[100005];
ll maxn=0,tem=0;
int main()
{
   
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
    {
   
        scanf("%d",&a[i]);
        if(a[i]>0)tem+=a[i];
    }
    ll zh=0,fu=0;
    for(int i=0;i<k;i++)
    {
   
        if(a[i]>0)zh+=a[i];
        else fu+=a[i];
    }
    if(zh>-fu)maxn=max(maxn,tem+fu);
    else maxn=max(maxn,tem-zh);
    for(int i=k;i<n;i++)
    {
   
        if(a[i-k]>0)zh-=a[i-k];
        else fu-=a[i-k];
        if(a[i]>0)zh+=a[i];
        else fu+=a[i];
        if(zh>-fu)maxn=max(maxn,tem+fu);
        else maxn=max(maxn,tem-zh);
    }
    printf("%lld",maxn);
    return 0;
}

C-Tetromino Tiling

题意:

给出几种俄罗斯方块的个数,让你求最多用k个俄罗斯方块能拼成高度为2,长为2k的矩形。矩形必须是实心的。

solution:

先求出如何用俄罗斯方块拼成完整的矩形。发现第三个、第六个、第七个没有用处。2个第一种;或1个第二种;或2个第四种;或2个第五种,或奇数个第一种,1个第四种,1个第五种;或偶数个第一种,2个第四种;或偶数个第一种,2个第五种。
然后贪心求解。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
ll a[10];
int main()
{
   
    for(int i=0;i<7;i++)scanf("%lld",&a[i]);
    ll res=0;
    res=a[0]/2*4+a[1]*2+a[3]/2*4+a[4]/2*4;
    if(a[0]%2)
    {
   
        if(a[3]&&a[4])
        {
   
            if(a[3]%2==1&&a[4]%2==1)
                res+=6;
            else if(a[3]%2==1)
                res+=2;
            else if(a[4]%2==1)
                res+=2;
        }
    }
    else if(a[0])
    {
   
        if(a[3]%2==1&&a[4]%2==1)
            res+=2;
    }
    printf("%lld",res/2);
    return 0;
}

D-K-th K

题意:

给了你一个长度为n的数组x,让你构造一个数组使得i第i次出现的位置在 x i x_i xi位置上,1-n的每个数都出现n次。

solution:

贪心。先将数组x按从小到大排序,然后先在 x i x_i xi位置上放上原来的下标的那个数,然后再从vis数组中从前往后枚举,放入相应数字(而不能从 x i x_i xi往前枚举,因为这样前面就可能出现空位,后面的数就不能放了),枚举完所有的x后。然后类似的贪心枚举后面的。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
int n;
struct node
{
   
    int x,id;
    bool operator <(const node pp)const
    {
   
        return x<pp.x;
    }
}p[505];
int vis[300005];
int main()
{
   
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
   
        scanf("%d",&p[i].x);
        p[i].id=i;
    }
    sort(p+1,p+1+n);
    memset(vis,0,sizeof(vis));
    bool flag=true;
    for(int i=1;i<=n;i++)
    {
   
        int pos=p[i].x;
        int c=p[i].id-1;
        if(vis[pos])flag=false;
        vis[pos]=p[i].id;
        pos=1;
        while(pos<p[i].x)
        {
   
            if(c==0)break;
            if(vis[pos]){
   pos++;continue;}
            vis[pos++]=p[i].id;
            c--;
        }
        if(c>0){
   flag=false;break;}
    }
    for(int i=1;i<=n;i++)
    {
   
        int pos=p[i].x+1;
        int c=n-p[i].id;
        while(pos<=n*n)
        {
   
            if(c==0)break;
            if(vis[pos]){
   pos++;continue;}
            vis[pos++]=p[i].id;
            c--;
        }
        if(c>0){
   flag=false;break;}
    }
    if(flag)
    {
   
        printf("Yes\n");
        for(int i=1;i<=n*n;i++)printf("%d ",vis[i]);
    }
    else printf("No");
    return 0;
}

E-Next or Nextnext

F-Black Radius

G-An Ordinary Game

题意:

给了一个字符串,你可以取出其中的一个字母的前提是,这个字符的两边还有字母,并且去掉这个字母后,断后重连的相邻两个字母不相同。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
string s;
int main()
{
   
    cin>>s;
    int n=s.length()-2;
    if(s[0]==s[s.length()-1])n--;
    if(n%2==0)printf("Second");
    else printf("First");
    return 0;
}

H-Cosmic Rays

题意:

给了起点和终点,以及n个圆圆心坐标和半径。问最短的从起点到终点的距离是多少(经过圆的那部分长度不算距离)。

solution:

另类的最短路。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
int sx,sy,tx,ty,n;
struct node
{
   
    int x,y,id,r;
    double d;
    bool operator>(const node pp)const
    {
   
        return d>pp.d;
    }
}p[1005];
int vis[1005];
void dijktra()
{
   
    priority_queue<node,vector<node>,greater<node>>que;
    que.push(p[0]);
    while(!que.empty())
    {
   
        node tem=que.top();que.pop();
        if(vis[tem.id])continue;
        vis[tem.id]=1;
        for(int i=1;i<=n;i++)
        {
   
            if(i==tem.id)continue;
            double dis=sqrt(1ll*(tem.x-p[i].x)*(tem.x-p[i].x)+1ll*(tem.y-p[i].y)*(tem.y-p[i].y));
            if(dis>p[i].r+tem.r&&tem.d+dis-p[i].r-tem.r<p[i].d)
            {
   
                p[i].d=tem.d+dis-p[i].r-tem.r;
                que.push(p[i]);
            }
            else if(dis<=p[i].r+tem.r&&tem.d<p[i].d)
            {
   
                p[i].d=tem.d;
                que.push(p[i]);
            }
        }
    }
}
int main()
{
   
    scanf("%d%d%d%d",&sx,&sy,&tx,&ty);
    scanf("%d",&n);
    p[0].x=sx;p[0].y=sy;p[0].d=0;p[0].id=0;p[0].r=0;
    for(int i=1;i<=n;i++)
    {
   
        scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].r);
        p[i].id=i;
        p[i].d=1e18;
    }
    n++;
    p[n].x=tx;p[n].y=ty;p[n].id=n;p[n].d=1e18;p[n].r=0;
    dijktra();
    printf("%.10f",p[n].d);
    return 0;
}

I-Rotated Palindromes

J-Connectivity

题意:

给了你n个城市,k条路,l条高铁,问每个城市与几个城市是可达的(既要有路,又要有高铁),自己与自己也是可达的。

solution:

先分别对高铁和路进行并查集,然后寻找同一个点在哪两个集合,进行hash设置唯一标识,记录数量,只有标识相同代表这个城市与其他的标识相同的城市之间是可达的。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
int n,k,l;
int f[200005],f1[200005];
ll ha=3e5;
map<ll,int>mp;
int Find(int fa[],int x){
   return fa[x]==x?x:fa[x]=Find(fa,fa[x]);}
void Union(int fa[],int x,int y)
{
   
    x=Find(fa,x);
    y=Find(fa,y);
    fa[x]=y;
}
int main()
{
   
    scanf("%d%d%d",&n,&k,&l);
    for(int i=1;i<=n;i++)f[i]=f1[i]=i;
    for(int i=0;i<k;i++)
    {
   
        int u,v;scanf("%d%d",&u,&v);
        Union(f,u,v);
    }
    for(int i=0;i<l;i++)
    {
   
        int u,v;scanf("%d%d",&u,&v);
        Union(f1,u,v);
    }
    for(int i=1;i<=n;i++)
        mp[1ll*ha*Find(f,i)+Find(f1,i)]++;
    for(int i=1;i<=n;i++)
        printf("%d ",mp[1ll*ha*Find(f,i)+Find(f1,i)]);
    return 0;
}

K-Manhattan Compass

L-Shuffling