ZUST 集训队19菜鸡互啄-4

A-Tournament
签到题 瞎搞就行了

#include<bits/stdc++.h>
using namespace std;
int t[60],a[60];
int main()
{
    int n,x,y;
    cin>>n;
    int cnt=n*(n-1)/2;
    for(int i=1;i<cnt;i++)
    {
        cin>>x>>y;
        t[x]++;
        t[y]++;
        a[x]++;
    }
    x=y=0;
    for(int i=1;i<=n;i++)
    {
        if(t[i]!=(n-1))
        {
            if(x!=0)y=i;
            else x=i;
        }
    }
    if(a[x]>=a[y])cout<<x<<" "<<y;
    else cout<<y<<" "<<x<<endl;
    return 0;
}

B-pSort
题目大意:有一个n个数的序列初始值是1-n有序排列,给一个目标序列和每一位下标的值di,di的意义是|i-j|=di的数可交换即(i+di)(i-di)和i和交换。每一位可交换无数次,问能不能从初始序列交换成目标序列。
分析:可用并查集把所有能交换数归成一个集合,最后查目标序列i 和ai是不是都是一个集合的就行了

#include<bits/stdc++.h>
using namespace std;
int fa[110],a[110];
int find(int x)
{
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
void cp(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    {
        fa[fx]=fy;
    }
}
int main()
{
    int n,x;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)
    {
        cin>>x;
        int y=i+x;
        if(y<=n)
        {
            cp(i,y);
        }
        y=i-x;
        if(y>0)cp(i,y);
    }
    for(int i=1;i<=n;i++)
    {
        if(a[i]!=i)
        {
            if(find(i)!=find(a[i]))
            {
                puts("NO");
                return 0;
            }
        }
    }
    puts("YES");
    return 0;
}

c-Traffic Lights
签到题,注意题目中交代的红灯计算规则,想到2 1 1 1 1这个样例就可

#include<bits/stdc++.h>
using namespace std;
int main()
{
    double l,d,v,g,r,ans;
    cin>>l>>d>>v>>g>>r;
    ans=l*1.0/v;
    double tmp=d*1.0/v+0.000000000001,tot=g+r;
    while(tmp>tot)tmp-=tot;
    if(tmp >g)ans+=(r+g-tmp);
    printf("%.8lf\n",ans);
    return 0;
}

D-Volleyball
题目大意:城市里面有n个交叉路口,m条路,每条无向有长度,每个交叉路口都有一个出租车司机等待,出租车可以行使长度不超过ti的距离,花费为ci。告诉你起始路口,问到达目标路口的最小花费。
思路:求最小花费,可以转化为最短路问题。首先我们可以根据m条路对每个路口出租车司机可以到达的路口和花费建图,然后求新建图的最短路即可。建图时也需要用到最短路,要求出定距离可以到达最多的点。还有就是求最短路时初始值一定要足够大,因为wi是10^9.

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
struct node
{
    int to,l,next;
}e[maxn*2];
struct bian{int l,u;};
const int inf=0x3f3f3f3f;
int head[maxn],vis[maxn];
long long int dis[maxn],t[maxn],c[maxn],mp[maxn][maxn];
int cnt,n,m,st,ed;
void add(int x,int y,int l)
{
    e[cnt].l=l;
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
void bfs(int l,int cost,int u)
{
    bian p,pp;
    int s=u;
    p.l=l,p.u=u;
    queue<bian> q;
    q.push(p);
    while(!q.empty())
    {
        p=q.front();
        q.pop();
        u=p.u;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            pp.l=p.l-e[i].l;
            if(pp.l>=0)
            {
                mp[s][v]=min(mp[s][v],(long long)cost);
                if(!vis[v])
                {
                    vis[v]=1;
                    pp.u=v;
                    q.push(pp);
                }
            }
        }
    }
}
long long int dij()
{
    for(int i=1;i<=n;i++)
    {
        vis[i]=0;
        dis[i]=1e15;
    }
    dis[st]=0;
    for(int i=1;i<=n;i++)
    {
        int x=-1;
        long long int tmp=1e15;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j] && dis[j]<tmp)
            {
                x=j;
                tmp=dis[j];
            }
        }
        //cout<<x<<endl;
        if(x==-1)break;
        vis[x]=1;
        for(int j=1;j<=n;j++)
        {
            if(!vis[j])
            {
                dis[j]=min(dis[j],(long long)(dis[x]+mp[x][j]));
            }
        }
    }
    return dis[ed];
}
int main()
{
    int x,y,l;
    cin>>n>>m>>st>>ed;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y>>l;
        add(x,y,l);
        add(y,x,l);
    }
    for(int i=1;i<=n;i++)
    {
        cin>>t[i]>>c[i];
        for(int j=1;j<=n;j++)mp[i][j]=(1e15);
    }
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        vis[i]=1;
        bfs(t[i],c[i],i);
    }
    long long int ans=dij();
    if(ans>=(1e15))puts("-1");
    else cout<<ans<<endl;
    return 0;
}

E-Name
题意:给你两个字符串s、t,输出由s组成的字符的一个排列,使得s字典序大于t,且字典序尽可能小
做法,贪心,要使字典序尽可能小又要大于t的字典序,则应该使得答案串与t串的前缀尽可能多的相同
然后就分两步走了
1 如果s中包含了t中的所有字符,且有多余的字符(因为字典序要严格大于t),则直接输出t,在接在后面输出剩下的字符的最小字典序的一个排列
2 假如1的条件不成立,就找这样一个位置,这个位置之前的字符都可以做到和t相同,且这个位置的字符要比t相应位置大,
因为要是前缀尽可能多的相同,所以贪心的从后往前求这个位置,找到这个位置后就可以把s中剩下的字符一并输出了

#include <bits/stdc++.h>
const int maxn = 5010;
char s[maxn];
char t[maxn];
int a[30], b[30];
int main()
{
    int i, j, k, l;
    bool can, flag;
    scanf("%s%s", s, t);
    can = true;
    int lens = strlen(s);
    int lent = strlen(t);
    for (i = 0; i < lens; i++)
        a[s[i] - 'a']++;
    for (i = 0; i < lent; i++)
        b[t[i] - 'a']++;
    int more = 0;
    for (i = 0; i < 26; i++)
    {
        if (a[i] < b[i])
            can = false;
        if (a[i] > b[i])
            more++;
    }
    int cnt;
    if (can && more)
    {
        cnt = lent;
        for (i = 0; i < 26; i++)
            for (j = 0; j < a[i] - b[i]; j++)
                t[cnt++] = 'a' + i;
        t[cnt] = '\0';
        printf("%s\n", t);
        return 0;
    }
    flag = false;
    for (i = lent - 1; i >= 0; i--)
    {
        can = true;
        b[t[i] - 'a']--;
        for (j = 0; j < 26; j++)
            if (a[j] < b[j])
                can = false;
        if (!can)
            continue;
        for (j = 0; j < 26; j++)
            if (j > t[i] - 'a' && a[j] > b[j])
            {
                flag = true;
                a[j]--;
                t[i] = 'a' + j;
                cnt = i + 1;
                for (i = 0; i < 26; i++)
                    for (j = 0; j < a[i] - b[i]; j++)
                        t[cnt++] = 'a' + i;
                t[cnt] = 0;
                printf("%s\n", t);
                break;
            }
        if (flag)
            break;
    }
    if (!flag)
        printf("-1\n");
    return 0;
}

F-Cubes
题意:给你n个数 m种颜色 最多可以删k个数 问你最长连续颜色相同的序列长度是多少
vector存每个颜色的位置,然后之后用尺取法,最后取最大的就好了

#include <bits/stdc++.h>
using namespace std;
vector<int>v[111111];
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
        for (int i = 1 ; i <= n ; i++ )
        {
            int a;
            scanf("%d",&a);
            v[a].push_back(i);
        }
        int res = 1;
        for (int i = 1 ; i <= m ; i++ )
        {
            int x = v[i].size();
            int temp = 1;
            int cou = 0;
            int y = 0;
            for(int j = 1 ; j < x  ; j ++ )
            {
                temp++;
                cou += v[i][j] - v[i][j-1] - 1;
                while ( cou > k)
                {
                    temp--;
                    cou -=v[i][y+1] - v[i][y] - 1;
                    y++;
                }
                if ( res < temp)
                {
                    res = temp;
                }
                
            }
        }
        printf("%d\n",res);
}

G-Weak Memory
题目大意:给你一些关键点,然后从关键点可以充能,然后每走一步消耗1能量,然后问是否能从s走到t,问消耗P最大的最小。可二分能量P验证也可搜索。
这里用的是基于优先队列的BFS

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int inf=0x3f3f3f3f;
struct node
{
    int to,next;
}e[maxn*2];
struct lu
{
    int u;
    int cost;
    bool operator <(const lu &k)const{
        return k.cost<cost;
    }
}p,pp;
int head[maxn],dis[maxn];
int cnt,n,k,m,x,y,st,ed;
int a[maxn];
void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
priority_queue<lu> q;
int bfs()
{
    int ans=0;
    p.u=st;
    p.cost=0;
    q.push(p);
    for(int i=1;i<=n;i++)dis[i]=inf;
    dis[st]=0;
    while(!q.empty())
    {
        p=q.top();
        q.pop();
        int u=p.u;
        if(p.cost>dis[u])continue;
        ans=max(ans,p.cost);
        if(u==ed)return ans;
        if(a[u])dis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next)
        {          
            int v=e[i].to;
            if(dis[v]>dis[u]+1)
            {
                dis[v]=dis[u]+1;
                pp.u=v;
                pp.cost=dis[v];
                q.push(pp);
            }
        }
    }
    return dis[ed];
}
int main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=k;i++)
    {
        cin>>x;
        a[x]=1;
    }
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    cin>>st>>ed;
    int ans=bfs();
    if(ans==inf)puts("-1");
    else cout<<ans<<endl;
    return 0;
}

H-Divisible by Seven
给一个数,这个数包含1689,随意调换数字的位置,构造一个mod 7 = 0 的数字
为什么要包含1689这四个数字呢?就是因为1689可以构造出mod 7 = {0, 1 … 6 } 的所有数字.这样就可以挑出个1689 ,根据剩下的数字 mod 7 的余数, 得到适当的数字,加到那个数字的后面根据同余的运算规则,总可以构造出来。建议暴力找规律,规律之一在代码里有实现

#include<bits/stdc++.h>
using namespace std;
string s[10];
int main()
{
    s[0]="1869";
    s[1]="6198";
    s[2]="1896";
    s[3]="1689";
    s[4]="9168";
    s[5]="6189";
    s[6]="1698";
    string c;
    cin>>c;
    int l=c.size();
    int a[22]={0};
    for(int i=0;i<l;i++)
    {
        a[c[i]-'0']++;
    }
    a[1]--;
    a[9]--;
    a[6]--;
    a[8]--;
    string ans="";
    int m=0;
    for(int i=1;i<10;i++)
    {
        for(int j=1;j<=a[i];j++)
        {
            m=(m*10+i)%7;
            ans+='0'+i;
        }
    }
    ans+=s[m];
    for(int i=1;i<=a[0];i++)ans+='0';
    cout<<ans<<endl;
    return 0;
}

I-Shooting Gallery
题意:给出n个靶子的坐标(x, y),出现的时间t,以及击中靶子的概率p;枪每秒移动一个单位的距离;问击中靶子数的期望最大值;
思路:dp[i] 表示到i为止击中靶子数的期望最大值;

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
struct node
{
    int x,y,t;
    double p;
    bool operator <(const node &k)const
    {
        return t<k.t;
    }
}a[maxn];
double dp[maxn],ans=0;
double dis(double x1, double y1, double x2, double y2)
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].x>>a[i].y>>a[i].t>>a[i].p;
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
    {
        dp[i]=a[i].p;
        for(int j=1;j<i;j++)
        {
            if(a[i].t-a[j].t>=dis(a[i].x, a[i].y, a[j].x, a[j].y))
					dp[i] = max(dp[i], dp[j]+a[i].p);      
        }
        ans=max(dp[i],ans);
    }
    printf("%.10f\n",ans);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值