2017年浙江工业大学大学生程序设计迎新赛决赛题解
【题目链接】:https://www.nowcoder.com/acm/contest/63#question
【暴力题】
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
空间限制: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
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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个国家若是想建立外交关系,则需要互相在对方的一块土地上建立一个大使馆。
一块土地只能建立一个大使馆,若一个国家和其他国家存在外交关系,则需要征用一块己方土地作为备用大使馆。
完美结局的定义是:找到最多数量的国家,使他们相互之间存在外交关系。
冲在每场战争的前线——无论您在哪里,他们都能找到您。骑小白兔飞驰吧,凶猛的女王,但愿您有真正的朋友和软弱的敌人。”
今天,冰雪聪明的栗酱终于玩到了她梦寐很久的文明游戏。
不过作为一个萌新,兔头獐脑的栗酱自然不愿意第一次玩就遇到一个尴尬的结局,于是希望通过你来寻找一个完美结局。
已知游戏结束前场上有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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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
【代码】:
dp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
题目描述
栗酱有一个长度为n的数列A,一个长度为m的数列B,现在询问A中有多少个长度为m的连续子序列A',
满足(a'1+b1)%k = (a'2+b2)%k = …… = (a'm + bm)%k。
满足(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/暴力匹配
【代码】:
暴力匹配
kmp
二分搜索可行解
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
题目描述
有不等式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可用二分搜索某可行解。
【代码】:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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); } }