2017年浙江工业大学大学生程序设计迎新赛决赛题解

【题目链接】:https://www.nowcoder.com/acm/contest/63#question

 

 【暴力题】


 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

        栗酱突发闲心,玩了一会儿仙剑。
        她玩的这个版本的仙剑非常简单,打架的时候,每次只有一个小怪,栗酱也只有一个主角,主角在每回合开始先攻击小怪,小怪有a点生命值,主角有b点生命值,小怪有c点攻击力,主角有d点攻击力,每次攻击都会造成确确实实的攻击力的伤害。
        生命值小于等于零时就会挂掉。
        栗酱发现好像战斗一开始就已经能知道结果了,请你帮她算一下,这样她就可以挂机去做更有趣的事了。
        数据保证攻击力和初始生命值均大于等于1。

输入描述:

第一行一个数据组数T。
每组数据一行4个整数a,b,c,d,数据之间用一个空格隔开。

输出描述:

对于每组数据每行给出一个"Yes"或"No",代表栗酱能否取得胜利。
示例1

输入

2
1 2 3 4
84 3 23 6

输出

Yes
No

说明

样例1解释:
第一回合时栗酱先发动攻击,小怪的生命值:1−4≤0,所以栗酱取得了胜利。

备注:

T≤1000,
1≤a,b,c,d≤1000
【代码】:
#include <bits/stdc++.h>

using namespace std;

int a,b,c,d;
int t;
bool f;
int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d",&a,&b,&c,&d);
        while(1)
        {
            a-=d;

            if(a<=0){
                f=true;//win
                break;
            }
            b-=c;

            if(b<=0){
                f=false;
                break;
            }
        }
        if(f){
            puts("Yes");
        }
        else{
            puts("No");
        }
    }


}

 

题目描述

        “伟大的勇栗兔栽栗女王,所有栗子看到您都不寒而栗,但也非常尊重您。您骑着威风凛凛的小白兔,带领栗子们奋勇前行。伟大史诗告诉我们,烈兔勇栗从大草原飞奔出来,
冲在每场战争的前线——无论您在哪里,他们都能找到您。骑小白兔飞驰吧,凶猛的女王,但愿您有真正的朋友和软弱的敌人。”
今天,冰雪聪明的栗酱终于玩到了她梦寐很久的文明游戏。
不过作为一个萌新,兔头獐脑的栗酱自然不愿意第一次玩就遇到一个尴尬的结局,于是希望通过你来寻找一个完美结局。

        已知游戏结束前场上有n个国家,第i个国家有ai块土地,任意2个国家若是想建立外交关系,则需要互相在对方的一块土地上建立一个大使馆。
一块土地只能建立一个大使馆,若一个国家和其他国家存在外交关系,则需要征用一块己方土地作为备用大使馆。
        完美结局的定义是:找到最多数量的国家,使他们相互之间存在外交关系。

输入描述:

第一行一个数T,表示有T组数据。
对于每组数据,第一行输入一个数n,表示国家的数量,接下来一行输入n个数,a1,a2,…,an,其中ai表示第i个国家拥有的土地数量。每两个相邻的数之间用空格隔开。

输出描述:

对于每一个询问,输出一个数,即完美结局下,相互建立外交关系的国家数量。
示例1

输入

2
5
2 2 2 2 2
10
8 6 5 9 2 7 10 3 3 9

输出

2
6

说明

对于第一个样例:
最多只能找到2个国家,使他们互相建立外交关系。
对于第二个样例:
第1,2,4,6,7,10个国家间可互相建立外交关系,最多数量为6。

备注:

T≤10
1≤n≤1000
1≤ai≤n
 
#include <bits/stdc++.h>

using namespace std;
const int N = 1010;
int n,a[N];
int t,ans,j;
bool f;
int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+n+1);

        for(int i=n,j=0; i>=1; i--,j++){
            a[i]-=j;
            //printf("i=%d,j=%d,a[i]=%d\n",i,j,a[i]);//
            if(a[i]<=0){
                ans=j;
                break;
            }
        }
        printf("%d\n",ans);
    }
}
模拟

 

题目描述

        栗酱一个人闲得无聊的时候总是会一个人玩一些有趣的游戏。
        有一天,她在机房里看见了一张图,可能是做acm的学长留下的:

        栗酱想知道每一个数字,横着竖着分别有几根火柴呢?(由于火柴商偷工减料,我们认定,只要存在棍子,它就是火柴!)

输入描述:

第一行一个数据组数T。
每组数据一行给出一个数字'a'。

输出描述:

对于每个数字给出两个值,分别是横着有几根火柴,竖着有几根火柴。
示例1

输入

1
0

输出

2 4
#include <bits/stdc++.h>
#include <map>

using namespace std;
const int N = 1010;
int n;
int t,ansx,ansy;
string s;
map<int, pair<int,int> >mp;
//不能在全局初始化STL
int x;
int main()
{
        mp[0].first=2;
        mp[0].second=4;

        mp[1].first=0;
        mp[1].second=2;

        mp[2].first=3;
        mp[2].second=2;

        mp[3].first=3;
        mp[3].second=2;

        mp[4].first=1;
        mp[4].second=3;

        mp[5].first=3;
        mp[5].second=2;

        mp[6].first=3;
        mp[6].second=3;

        mp[7].first=1;
        mp[7].second=2;

        mp[8].first=3;
        mp[8].second=4;

        mp[9].first=3;
        mp[9].second=3;
    scanf("%d",&t);
    while(t--){
       cin>>s;
       for(int i=0; i<s.size(); i++){
         ansx += mp[ ((s[i]-'0')%10) ].first;
         ansy += mp[ ((s[i]-'0')%10) ].second;
         x=s[i]-'0';
         x/=10;
       }
       printf("%d %d\n",ansx,ansy);
       //mp.clear();
       ansx=ansy=0;

    }
}
模拟

 

【基础算法题】


 

题目描述

给定两个长度为n的整数列A和B,每次你可以从A数列的左端或右端取走一个数。假设第i次取走的数为ax,则第i次取走的数的价值vi=bi⋅ax,现在希望你求出∑vi的最大值。

输入描述:

第一行一个数T,表示有T组数据。
对于每组数据,第一行一个整数n,
接下来两行分别给出A数列与B数列。

输出描述:

每一组数据输出一行,最大的∑vi。
示例1

输入

2
2
1 1000
2 1
5
1 3 5 2 4
1 2 3 4 5

输出

2001
52

说明

对于第二个样例,
第一次从左边取走a1,v1=a1⋅b1=1,
第二次从左边取走a2,v2=a2⋅b2=6,
第三次从右边取走a5,v3=a5⋅b3=12,
第四次从右边取走a4,v4=a4⋅b4=8,
第五次取走剩下的a3,v5=a3⋅b5=25。
总价值∑vi=1+6+12+8+25=52

备注:

T≤10
1≤n≤103
1≤ai,bi≤103
【分析】:基本区间DP。
【相似】:http://tyvj.joyoi.cn/Solution/6645    https://www.cnblogs.com/yangqingli/p/4735607.html  https://www.cnblogs.com/EdSheeran/p/6701200.html
【代码】:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int a[1010],b[1010];
int dp[1010][1010];
int dfs(int l,int r,int time)
{
    if(l>r)return 0;
    if(dp[l][r])return dp[l][r];
    int temp=0;
    temp=max(temp,dfs(l+1,r,time+1)+b[time]*a[l]);
    temp=max(temp,dfs(l,r-1,time+1)+b[time]*a[r]);
    return dp[l][r]=temp;
}
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        printf("%d\n",dfs(1,n,1));
    }
    return 0;
}
dp

 

题目描述

栗酱有一个长度为n的数列A,一个长度为m的数列B,现在询问A中有多少个长度为m的连续子序列A',
满足(a'1+b1)%k = (a'2+b2)%k = …… = (a'm + bm)%k。

输入描述:

第一行一个数T,表示有T组数据。
对于每组数据,
第一行三个整数,n, m, k。
第一行输入n个数, a1,a2,…,an, 表示A数列中的数,
第二行输入m个数, b1,b2,…,bm, 表示B数列中的数。

输出描述:

每一组数据输出一行,满足条件的连续子序列数量。
示例1

输入

2
3 2 5
7 8 7
8 7
3 2 5
7 8 9
8 7

输出

1
2

备注:

T≤15,
2≤m≤n≤2×105,
1≤ai,bi,k≤109
【分析】:kmp/暴力匹配
【代码】:
#include<bits/stdc++.h>
using namespace std;
int a[200005],b[200005];
int main()
{
    
    int T;
    int n, m, k, i, j;
    scanf("%d", &T);
    while(T--)
    {
        int count=0;
        scanf("%d%d%d", &n, &m, &k);
        for(i=0;i<n;i++)
            scanf("%d", &a[i]);
        for(i=0;i<m;i++)
            scanf("%d", &b[i]);
        for(i=0;i<n;i++)
        {
             for(j=0;j<m-1;j++)
             {
                 if((a[i+j]+b[j])%k==(a[i+j+1]+b[j+1])%k)
                     continue;
                 else
                     break;
             }
             if(j==m-1)
                 count++;
        }
        printf("%d\n", count);
    }
    return 0;
}
暴力匹配

 

#include <bits/stdc++.h>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define mp(x, y) make_pair(x, y)
#define pb(x) push_back(x)
#define X first
#define Y second
#define fastin                    \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);
typedef long long ll;
typedef long double ld;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-6;
 
// 返回y中x的个数
const int N = 1 << 18;
int Next[N];
void initkmp(int x[], int m)
{
    int i = 0, j = Next[0] = -1;
    while (i < m)
    {
        while (j != -1 && x[i] != x[j]) j = Next[j];
        Next[++i] = ++j;
    }
}
int kmp(int x[], int m, int y[], int n)
{
    int i, j, ans;
    i = j = ans = 0;
    initkmp(x, m);
    while (i < n)
    {
        while (j != -1 && y[i] != x[j]) j = Next[j];
        i++, j++;
        if (j >= m) ans++, j = Next[j];
    }
    return ans;
}
 
int a[N], b[N];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int T;
    scanf("%d", &T);
    while (T--)
    {
        int n, m, k;
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 0; i < n; i++) scanf("%d", &a[i]);
        for (int i = 0; i < m; i++) scanf("%d", &b[i]);
        for (int i = 0; i < n; i++) a[i] %= k;
        for (int i = 0; i < m; i++) b[i] = (k - b[i] % k) % k;
        for (int i = 0; i < n - 1; i++) a[i] = (a[i + 1] - a[i] + k) % k;
        for (int i = 0; i < m - 1; i++) b[i] = (b[i + 1] - b[i] + k) % k;
        printf("%d\n", m - 1 ? kmp(b, m - 1, a, n - 1) : n);
    }
    return 0;
}
kmp

 

题目描述

有不等式y⋅x3≤ n,已知y为正整数,x为大于1的正整数,问当x和y的解数量刚好为m的时候n的最小值,如果不存在输出 -1。

输入描述:

多组数据读入。
每组数据一个数字m,如题所示。

输出描述:

每组数据输出一行,输出答案。
示例1

输入

1

输出

8

说明

当方案恰好只有一种的时候,n的最小值为8,此时y=1,x=2。

备注:

1 ≤ m ≤ 1016

【分析】:找满足某条件check(n)的最小/最大的x可用二分搜索某可行解。

【代码】:

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

ll check(ll cnt)
{
    ll ans=0;
    for(ll x=2; x*x*x<=cnt; x++) ans+=cnt/(x*x*x);
    return ans;
}
int main()
{
    ll m;
    while(~scanf("%lld",&m)){//记得~!!!
    ll l=1,r=1e16,mid;
    while(l<=r){
        mid=(l+r)/2;
        if(check(mid)>=m)
            r=mid-1;
        else
            l=mid+1;
    }
    printf("%lld\n",check(l)==m?l:-1);
    }
}
二分搜索可行解

 

转载于:https://www.cnblogs.com/Roni-i/p/8093120.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值