2017gdut校赛初赛题解

题目来源:http://www.gdutcode.sinaapp.com/contest.php?cid=1054

Problem A: An easy problem

解析:标准签到题,(⊙o⊙)…,直接输出Accept,A不大写的人不知道什么心态

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
using namespace std;
int main()
{
    puts("Accept");
    return 0;
}

Problem B: Tmk吃汤饭

解析:很有规律的一个序列,我没去推公式而是直接打的表…公式应该是 (n/4+1)*5+(n%4+1)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
using namespace std;
const int maxn = 10050;
int a[maxn];
int main()
{
    a[0] = 6;
    for(int i=1;i<maxn;i++)
    {
        a[i] = a[i-1]+1;
        if(i%4==0)
            a[i]++;
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        printf("%d\n",a[n]);
    }
    return 0;
}

Problem C: 进击的调查兵团

解析:二分答案,二分答案出来以后在二分查找在每个序列里有多少个小于等于他的,stl是个好东西

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
using namespace std;
const int maxn = 1e5+100;
int a[maxn];
int b[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,q;
        scanf("%d %d %d",&n,&m,&q);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<m;i++)
            scanf("%d",&b[i]);
        while(q--)
        {
            int l1,r1,l2,r2,k;
            scanf("%d %d %d %d %d",&l1,&r1,&l2,&r2,&k);
            int l = min(a[l1],b[l2]),r = max(a[r1],b[r2]);
            while(l<r)
            {
                int mid = l+((r-l)/2);
                int pos1 = lower_bound(a+l1,a+r1+1,mid)-a;
                if(a[pos1]==mid)
                    pos1++;
                int pos2 = lower_bound(b+l2,b+r2+1,mid)-b;
                if(b[pos2]==mid)
                    pos2++;
                if(pos1+pos2<k+l1+l2)
                    l = mid+1;
                else
                    r = mid;
            }
            printf("%d\n",l);
        }
    }
    return 0;
}

Problem D: TMK的航拍图像

解析:没有重点,那么所有可能的线段是n*(n-1)/2,由于问的是直线,所以枚举两个点,判断是否和其他点相交如果相交就ans–

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
using namespace std;
const int maxn = 2e5+10;
struct point
{
    int x,y;
}a[maxn];
int n,m;
int x_mul(point p0,point p1,point p2)
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int main()
{
    //freopen("a.in","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d %d",&a[i].x,&a[i].y);
        int ans = n*(n-1)/2;
        for(int i=0;i<n;i++)
        {
            for(int j=i+1;j<n;j++)
            {
                for(int k=0;k<n;k++)
                {
                    if(k>=i && k<=j)
                        continue;
                    if(x_mul(a[k],a[i],a[j])==0)
                        ans--;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

Problem E: 绕远路

解析:dp题,dp[i][n]表示到点i长度为n是否可行,状态转移方程为:dp[tmp.v][tt] |= dp[i][tt-tmp.w],tmp.v到i之间有条长度为tmp.w的边

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
using namespace std;
const int maxn = 5000+40;
struct node
{
    int v,w;
    node() {}
    node(int _v,int _w)
    {
        v = _v;
        w = _w;
    }
};
vector<node>G1[maxn],G2[maxn];
int dp[maxn][maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(dp,0,sizeof(dp));
        int n,m,k;
        scanf("%d %d %d",&n,&m,&k);
        for(int i=1;i<=n;i++)
            G1[i].clear(),G2[i].clear();
        while(m--)
        {
            int u,v,l;
            scanf("%d %d %d",&u,&v,&l);
            if(u!=v)
            {
                if(u>v)
                    swap(u,v);
                G1[u].push_back(node(v,l));
            }
            else
                G2[u].push_back(node(v,l));
        }
        dp[1][0] = 1;
        for(int i=1;i<=n;i++)
        {
            for(unsigned j=0;j<G2[i].size();j++)
            {
                node tmp = G2[i][j];
                for(int tt=tmp.w;tt<=k;tt++)
                    dp[i][tt] |= dp[i][tt-tmp.w];
            }
            for(unsigned j=0;j<G1[i].size();j++)
            {
                node tmp = G1[i][j];
                for(int tt=tmp.w;tt<=k;tt++)
                    dp[tmp.v][tt] |= dp[i][tt-tmp.w];
            }
        }
        int ans = -1;
        for(int i=0;i<=k;i++)
        {
            if(dp[n][i])
                ans = i;
        }
        printf("%d\n",ans);
    }
    return 0;
}

Problem F: 密码锁

解析:每个齿轮转到想要的位置最少步数为:min((Ai-ai+10)%10,(ai-Ai+10)%10)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
using namespace std;
const int maxn = 10050;
int a[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        int ans = 0;
        while(n--)
        {
            int a1,b1,c1,d1;
            int a2,b2,c2,d2;
            scanf("%d %d %d %d",&a1,&b1,&c1,&d1);
            scanf("%d %d %d %d",&a2,&b2,&c2,&d2);
            ans += min((a1-a2+10)%10,(a2-a1+10)%10);
            ans += min((b1-b2+10)%10,(b2-b1+10)%10);
            ans += min((c1-c2+10)%10,(c2-c1+10)%10);
            ans += min((d1-d2+10)%10,(d2-d1+10)%10);
        }
        printf("%d\n",ans);
    }
    return 0;
}

Problem G: 知识来源于分解

解析:尺取维护答案

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
using namespace std;
const int maxn = 1e6+10;
char a[maxn];
int vis[100];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,k;
        scanf("%s %d",a,&k);
        n = strlen(a);
        int ans = 0;
        int l = 0,r = 0,cnt = 0;
        memset(vis,0,sizeof(vis));
        while(n-l>ans)
        {
            while(r<n)
            {
                if(vis[a[r]-'A'])
                    vis[a[r]-'A']++;
                else
                {
                    if(cnt+1>k)
                        break;
                    else
                        cnt++;
                    vis[a[r]-'A']++;
                }
                r++;
            }
            if(cnt == k)
                ans = max(ans,r-l);
            vis[a[l]-'A']--;
            if(vis[a[l]-'A']==0)
                cnt--;
            l++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

Problem H: 找正方形

解析:找到一点’#’,枚举正方形长度,判断是否合法

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
using namespace std;
const int maxn = 1e6+10;
char a[25][25];
bool slove(int x,int y,int n)
{
    for(int i=x;i<=x+n;i++)
    {
        if(a[i][y]!='#')
            return false;
        if(a[i][y+n]!='#')
            return false;
    }
    for(int i=y;i<=y+n;i++)
    {
        if(a[x][i]!='#')
            return false;
        if(a[x+n][i]!='#')
            return false;
    }
    return true;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%s",a[i]);
        int flag = 0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(a[i][j]=='#')
                {
                    for(int k=1;k<=n-1-i;k++)
                    {
                        if(i+k>=n || j+k>=n)
                            break;
                        if(slove(i,j,k))
                            flag = 1;
                    }
                }
            }
        }
        if(flag)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值