ZUST 集训队19届菜鸡互啄-1 题解

题解都是认真瞎几把 写的,看不懂的看代码

A-meeting 题目链接

题意让你求要带多少个毯子,即求有几个暖气片覆盖不到的点。暴力模拟即可。

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int x[1000], y[1000], r[1000], a, b, c, d, n, j, k, A = 0;
	cin >> a >> b >> c >> d >> n;
	for (int i = 0; i < n; ++i)
		cin >> x[i] >> y[i] >> r[i];

	for (int i = min(a, c); i <= max(a, c); i++)
	{
		for (j = min(b, d); j <= max(b, d); j++)
		{
			if (i == a || i == c || j == b || j == d)
			{
				for (k = n; k--;)
					if((i-x[k])*(i-x[k])+(j - y[k]) * (j - y[k]) <= r[k] *r[k])
						break;
				A += k < 0;//如果K小于0 则表示没有一个暖气片能覆盖到这个点
			}
		}
	}
	cout << A;
}

B-Tic-tac-toe题目链接

题意是给你一个井字棋让你判断当前棋的状态是否合法,合法的话有没有人赢,没人人能赢的话下一个谁下
暴力模拟就行 这个模拟 真香

#include<bits/stdc++.h>
using namespace std;
char a[5][5];
int cnt0,cntx;
bool win(char x)
{
    if(a[0][0]==x&&a[0][1]==x&&a[0][2]==x)return true;
    if(a[1][0]==x&&a[1][1]==x&&a[1][2]==x)return true;
    if(a[2][0]==x&&a[2][1]==x&&a[2][2]==x)return true;
    if(a[0][0]==x&&a[1][0]==x&&a[2][0]==x)return true;
    if(a[0][1]==x&&a[1][1]==x&&a[2][1]==x)return true;
    if(a[0][2]==x&&a[1][2]==x&&a[2][2]==x)return true;
    if(a[2][0]==x&&a[1][1]==x&&a[0][2]==x)return true;
    if(a[0][0]==x&&a[1][1]==x&&a[2][2]==x)return true;
    return false;
}
bool judge()
{
    if(win('X')&&cntx==cnt0)return true;
    if(win('0')&&cntx==cnt0+1)return true;
    if(cntx>cnt0+1||cntx<cnt0)return true;
    return false;
}
int main()
{
    for(int i=0;i<3;i++)
    {
        scanf("%s",a[i]);
    }
    cnt0=0,cntx=0;
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            if(a[i][j]=='0')
            {
                cnt0++;
            }
            if(a[i][j]=='X')
            {
                cntx++;
            }
        }
    }
    if(judge())
    {
        printf("illegal\n");
    }
    else if(win('0'))
    {
        printf("the second player won\n");
    }
    else if(win('X'))
    {
        printf("the first player won\n");
    }
    else if(cnt0+cntx==9)
    {
        printf("draw\n");
    }
    else if(cnt0==cntx)
    {
       printf("first\n");
    }
    else
    {
       printf("second\n");
    }
    return 0;
}

C-Spreadsheets题目链接
题意:题目给出了EXCEL行和列的两种表示方法,输入后判断是哪一种表示方法并把它转化成另一种
按题意模拟即可 字符和数字的转化可看成类似转化成26进制

#include<bits/stdc++.h>
using namespace std;
string s;
bool pd()
{
    for(int i=2;i<s.size();i++)
    {
        if(s[i]=='C')return true;
    }
    return false;
}
int main()
{
    string ans;
    int n,l,r;
    cin>>n;
    while(n--)
    {
        cin>>s;
        if(s[0]=='R' && s[1]>='0' &&s[1]<='9' && pd())
        {
            int i;
            r=l=0;
            for(i=1;s[i]!='C';i++)
            {
                l*=10;
                l+=s[i]-'0';
            }
            for(i=i+1;i<s.size();i++)
            {

                r*=10;
                r+=s[i]-'0';
            }
            ans="";
            while(r)
            {
                int tmp=r%26;
                char c=(tmp+'A'-1);
                if(tmp==0)c='Z',r-=26;
                ans+=c;
                r/=26;
            }
            for(int i=ans.size()-1;i>=0;i--)
            {
                cout<<ans[i];
            }
            cout<<l<<endl;
        }
        else
        {
            ans="";
            int i=0;
            l=r=0;
            for(i=0;s[i]>='A'&&s[i]<='Z';i++)
            {
                ans+=s[i];
            }
            for(i;i<s.size();i++)
            {
                r*=10;
                r+=s[i]-'0';
            }
            int tmp=1;
            for(i=ans.size()-1;i>=0;i--)
            {
                l+=tmp*(ans[i]-'A'+1);
                tmp*=26;
            }
            cout<<'R'<<r<<'C'<<l<<endl;
        }
    }
    return 0;
} 

D-Escape 题目链接
题目大意:公主要从龙洞跑路公主以每小时vp英里的速度奔跑,而龙则以每小时vd英里的速度飞行。龙会在t小时后发现逃跑的路,并会立刻追上公主。一旦龙抓住了公主,她就会扔下一个东西来分散龙的注意力。在这种情况下,他会停下来,拿起物品,回到洞穴,花上f个小时来整理库房里的东西。只有在这之后,他才会重新开始追逐。问要几个东西才能保证公主不会被抓回去。
模拟一下就是小学生的解方程题 要注意的是龙和公主同时到达城堡时不算龙抓住公主,

#include<bits/stdc++.h>
using namespace std;
int main()
{
    double vd,vp,c,t,f;
    int ans=0;
    cin>>vp>>vd>>t>>f>>c;
    if(vp>=vd)
    {
        cout<<0<<endl;
        return 0;
    }
    double l=vp*t;  //l表示公主逃跑距离 v表示龙与公主速度差
    double real_l=l+l*1.0/(vd-vp)*vp;
    while(real_l<c)
    {
        ans++;
        double ti=f+real_l*1.0/vd;
        l=real_l+vp*ti;
        real_l=l+l*1.0/(vd-vp)*vp;
    }
    cout<<ans<<endl;
    return 0;
}

E-Dijkstra题目链接

题目大意:看题目标题就是了,要记录一下路径
输入好像有1e5个点 边也只有1e5 果断spfa

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long int ll;
int head[maxn],pre[maxn],vis[maxn];
ll dis[maxn];
const ll inf=0x3f3f3f3f3f;
struct node
{
    int to,l,next;
}e[maxn*2];
int cnt,n,m;
void add(int x,int y,int l)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    e[cnt].l=l;
    head[x]=cnt++;
}
int dij(int s)
{
    queue<int> q;
	for(int i=0;i<=n;i++)
	{
		vis[i]=0;
		dis[i]=inf;
	}
	dis[s]=0;
	vis[s]=1;
	q.push(s);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i!=-1;i=e[i].next)
		{
			int v=e[i].to;
			if(dis[v]>dis[u]+e[i].l)
			{
                pre[v]=u;
				dis[v]=dis[u]+e[i].l;
				if(!vis[v])
				{
					vis[v]=1;
					q.push(v);
				} 
			}
		}
	}
    if(dis[n]==inf)return -1;
    return dis[n];
}
int main()
{
    cin>>n>>m;
    int x,y,l;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y>>l;
        add(x,y,l);
        add(y,x,l);
    }
    int ans=dij(1);
    if(ans==-1)cout<<-1<<endl;
    else
    {
        stack<int> q;
        int v=n;
        while(v!=1)
        {
            q.push(v);
            v=pre[v];
        }
        cout<<1;
        while(!q.empty())
        {
            cout<<" "<<q.top();
            q.pop();
        }
    }
    return 0;
}

F-The least round way题目链接
题目大意:给一个NN的矩阵,让你从1-1位置走到n-n每次只能向下或向右走,让你找一条路径使得路径上的点相乘后末尾的0的数量最少
考虑到末尾会出现0的情况大致可以分成三种,1.乘数中有一个0,这样的话最后结果就是0,2.乘数中有5和偶数,偶数和5相乘尾数会有0,3.乘数中有10的倍数.
每一个2
5会增加一个0 所以考虑把每一个位置上的数可以整除2几次和整除5几次记录下来,末尾0的个数就是2和5个数中小的那一个。然后把矩阵分别按2的个数和5的个数记忆化搜索一下,答案就是dp到n-n这个位置上2和5个数小的那一个。再倒推路径输出。需要特判一种情况就是有0,且正常求出时的答案大于1的时候。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int dp[maxn][maxn][3];
char mp[maxn][maxn][2];
int n,x,f=-1;
void print(int k)
{
    cout<<endl;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<dp[i][j][k]<<" ";
        }
        cout<<endl;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&x);
            if(x==0)f=i;
            else{
            while(x%2==0 && x)x/=2,dp[i][j][0]++;
            while(x%5==0 && x)x/=5,dp[i][j][1]++;}
        }
    }
    for(int i=2;i<=n;i++)
    {
        dp[1][i][0]+=dp[1][i-1][0];
        dp[1][i][1]+=dp[1][i-1][1];
        dp[i][1][0]+=dp[i-1][1][0];
        dp[i][1][1]+=dp[i-1][1][1];
    }
   
    for(int i=2;i<=n;i++)
    {
        for(int j=2;j<=n;j++)
        {
            dp[i][j][0]+=min(dp[i-1][j][0],dp[i][j-1][0]);
            dp[i][j][1]+=min(dp[i-1][j][1],dp[i][j-1][1]);
        }
    }
    int k=0;
    if(dp[n][n][1]<dp[n][n][0])k=1;
    if(f!=-1 && dp[n][n][k]>1)
    {
        cout<<1<<endl;
        for(int i=1;i<f;i++)cout<<'D';
        for(int i=1;i<n;i++)cout<<'R';
        for(int i=f;i<n;i++)cout<<'D';
        return 0;
    }
    printf("%d\n",dp[n][n][k]);
    int mx=n,my=n;
    string ans="";
    while(1)
    {
        if(mx==1)
        {
            for(;my>1;my--)ans+='R';
            break;
        }
        if(my==1)
        {
            for(;mx>1;mx--)ans+='D';
            break;
        }
        if(dp[mx-1][my][k]<dp[mx][my-1][k]){ans+='D';mx--;}
        else{ans+='R';my--;}
    }
    for(int i=ans.size()-1;i>=0;i--)
    {
        cout<<ans[i];
    }
    return 0;
}

G-Lorry题目链接

题目大意:有N个小船,每个小船的体积为1或2,每个小船有不同的载重。现有一载重为V的卡车,问卡车能拉走的小船的载重和的方案
考虑到数据范围,加上小船每个体积只有1和2,用贪心。先把体积为2的小船全部装上车,再考虑体积为1的小船能不能装上车或者替换掉车上的船

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct node
{
    int p,id;
}yi[maxn],er[maxn];
bool vis[maxn];
bool cnm(node a,node b)
{
    return a.p>b.p;
}
int main()
{
    int n,m,ans=0,x,y,z,cnt=0,tot=0,xx=0,yy=0;
    queue<int> s;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>x>>y;
        yy+=y;
        xx+=x;
        if(x==1)
        {
            yi[++cnt].p=y;
            yi[cnt].id=i;
        }
        else
        {
            er[++tot].p=y;
            er[tot].id=i;
        }
    }
    if(xx<=m)
    {
        cout<<yy<<endl;
        for(int i=1;i<=n;i++)cout<<i<<" ";
        return 0;
    }
    sort(er+1,er+tot+1,cnm);
    sort(yi+1,yi+cnt+1,cnm);
    int i=1,j=1;
    while(m>1 && j<=tot)
    {
        ans+=er[j].p;
        vis[er[j].id]=1;
        m-=2;
        j++;
    }
    j--;
    while(m>0 && i<=cnt)
    {
        m--;
        ans+=yi[i].p;
        vis[yi[i].id]=1;
        i++;
    }
    while(j>0 && i<=cnt)
    {
        if((yi[i].p+yi[i+1].p-er[j].p)>0)
        {
            ans+=(yi[i].p+yi[i+1].p-er[j].p);
            vis[yi[i].id]=vis[yi[i+1].id]=1;
            vis[er[j].id]=0;
            i+=2;
            j--;
        }
        else break;
    }
    cout<<ans<<endl;
    for(int i=1;i<=n;i++)
    {
        if(vis[i])cout<<i<<" ";
    }
    return 0;
}

H-Roads in Berland题目链接
题目大意:小镇上原来有每个城市之间的最短路径,现在考虑要修K条路,需要你来算修完这条路后每对城市之间的最短路和。
暴力枚举每对城市再加入这条路后的最短路有没有变化,具体实现看代码,每次加边后都要暴力一次。(反正数据小,暴它丫的)

#include<bits/stdc++.h>
using namespace std;
const int maxn=310;
int mp[maxn][maxn];
int main()
{
    int n,m,x,y,l;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)cin>>mp[i][j];
    }
    cin>>m;
    for(int k=1;k<=m;k++)
    {
        cin>>x>>y>>l;
        mp[x][y]=mp[y][x]=min(l,mp[x][y]);
        for(int i=1;i<=n;i++)//暴力枚举
        {
            for(int j=1;j<=n;j++)
            {
                mp[i][j]=mp[j][i]=min(mp[i][j],mp[i][x]+mp[x][y]+mp[y][j]);
            }
        }
        long long int ans=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)ans+=mp[i][j];
        }
        cout<<ans<<endl;
    }
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值