2020年西北工业大学“编程之星”序设计挑战赛(大学生程序设计创新实践基地队员冬季选拔赛) 部分题解

今天呢还是日常写各种打假算法~

但不得不说他们学校出的题质量还是很好的

运筹帷幄: dfs(细节~) 

考虑到数据范围很小,当然是神搜了~,其实6层for也是不错的选择,有几个细节很坑就是:只要被冰了就一直冰着,英雄攻击只能用一次!(弱弱就死在这里~),法术伤害叠加,英雄伤害不叠加。然后记录状态:

(当前剩余技能点val ,伤害总和num,法伤加成now,数组x,是否冰冻flag),

然后d就行了

链接:https://ac.nowcoder.com/acm/contest/11290/B
来源:牛客网
 

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
typedef  long long ll;
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
#define per(i,j,n) for(ll i=j;i>=n;i--)
#define pr(x) printf("%lld\n",x) 
typedef unsigned long long ull;
typedef unsigned int us;
const ll INF=1e18+7;const double eps=1e-8,pi=acos(-1);
const ll mod=1000000007;
const ll maxx=1e5+700;
inline bool read(ll &num){char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,h;
ll maxl=0;
map<string,ll>mp;
string a[10]={ "1","Frostbolt","IceLance","Fireball","BloodmageThalnos","CosmicAnomaly","Alexstrasza"};
ll cishu[20];
void dfs(ll val,ll num,ll now,ll x[],ll flag)   // 剩余 当前值  伤害, 数组 ,冰冻 
{
	if(val<0) return ;
	rep(i,1,5)
	{
		if(x[i]>cishu[i]) return ;
	}
	if(val>=0)
	{
	//	printf("%lld\n",num);
		maxl=max(maxl,num);
	}
	ll y[8];
	rep(j,1,5) y[j]=x[j];
	y[1]++;
	dfs(val-2,num+3+now,now,y,1);
	y[1]--;
	
	y[2]++;
	if(flag==0)
	dfs(val-1,num,now,y,1);
	else 
	dfs(val-1,num+4+now,now,y,1);
	y[2]--;
	
	y[3]++;
	dfs(val-4,num+6+now,now,y,flag);
	y[3]--;
	
	y[4]++;
	dfs(val-2,num,now+1,y,flag);
	y[4]--;
	
	y[5]++;
	dfs(val-4,num,now+2,y,flag);
	y[5]--;
	
	dfs(val-2,num+1,now,y,flag);
}

int main()
{
    ll t;
	cin>>n>>m>>h;
	string b;
	rep(i,1,n)
	{
		cin>>b;
		mp[b]++;
	}
	rep(i,1,5) cishu[i]=mp[a[i]];

	ll x[8]={0};
	dfs(m,0,0,x,0);
    //pr(maxl);
	if(maxl>=h) printf("Win\n");
	else 
	{
		printf("Lose\n");
		pr(maxl);
	}
	
	return 0;
}

题目描述

Korialstrasz和Neltharion正在打牌。现在局势对Korialstrasz非常不利,他已经不能活到下一个回合了,所以他想知道在这个回合内能否击败对手。

Korialstrasz的卡组是冰法,现在他拥有 n 张手牌,每张手牌均为以下 6 种卡牌中的一种:

 

    1. Frostbolt,消耗 2 点法力水晶,对一个角色造成 3 点伤害,并使其冻结
    2. IceLance,消耗 1 点法力水晶,冻结一个角色,如果该角色已被冻结,则改为对其造成 4 点伤害
    3. Fireball,消耗 4 点法力水晶,对一个角色造成 6 点伤害
    4. BloodmageThalnos,消耗 2 点法力水晶,你的法术伤害加 1
    5. CosmicAnomaly,消耗 4 点法力水晶,你的法术伤害加 2
    6. Alexstrasza,消耗 9 点法力水晶,将一名玩家的生命值变为 15(使用这张牌造成的生命值改变不视为伤害)


以上卡牌中BloodmageThalnos和Alexstrasza为传说卡,至多各有一张,其余卡牌至多各有两张。

在回合开始时Korialstrasz拥有 m 点法力水晶,使用卡牌会消耗相应的法力水晶,如果剩余的法力水晶数量小于卡牌消耗的法力水晶数量,则无法使用该卡牌。

除了使用手牌打出伤害,Korialstrasz还可以使用英雄技能,英雄技能每回合只能使用一次,会消耗 2 点法力水晶对一个角色造成 1 点伤害。

Neltharion的英雄拥有 h 点生命值,也就是说Korialstrasz本回合内只要造成至少 h 点伤害即可获胜。回合开始时 Neltharion 的英雄并没有被冻结。

输入描述:

 

第一行输入为 n,m,h,分别表示手牌数量,法力水晶数量与对手生命值。

之后 n 行每行输入一张卡牌的名称。

保证 0≤n≤100\le n \le 100≤n≤10,1≤m≤101\le m \le 101≤m≤10,1≤h≤301\le h \le 301≤h≤30。

输出描述:

如果Korialstrasz能够获胜,仅输出Win,否则输出两行,第一行输出Lose,第二行输出能够打出的最高伤害。

示例1

输入

复制10 10 20 IceLance Fireball Frostbolt CosmicAnomaly Fireball BloodmageThalnos IceLance Frostbolt Alexstrasza CosmicAnomaly

10 10 20
IceLance
Fireball
Frostbolt
CosmicAnomaly
Fireball
BloodmageThalnos
IceLance
Frostbolt
Alexstrasza
CosmicAnomaly

输出

复制Win

Win

说明

可以先打出一张CosmicAnomaly,然后依次打出两张Frostbolt与两张IceLance,造成5+5+6+6=22点伤害,消耗10点法力水晶。

示例2

输入

复制2 4 6 IceLance IceLance

2 4 6
IceLance
IceLance

输出

复制Lose 5

Lose
5

说明

伤害最高的打法是使用两张IceLance与一次英雄技能,造成0+4+1=5点伤害,消耗4点法力水晶,不足以击败对手。

示例3

输入

复制3 3 10 IceLance Frostbolt IceLance

3 3 10
IceLance
Frostbolt
IceLance

输出

复制Lose 7

Lose
7

说明

由于只有3点法力水晶,最多只能使用一张Frostbolt一张IceLance,造成7点伤害。

备注:

关于法术伤害的理解:在本题中,通过手牌造成的伤害均为法术伤害,享受法术伤害加成,而英雄技能造成的伤害不是法术伤害。法术伤害加成可以叠加,也不会随着法术的使用而衰减或消失。

D :玩具(思维?) 其实就输出个最多的数是谁就行

22233314111,

。假设当前最长的长度为len,最多数的种类有2个,且不包括最多的个数,比如 222333,如果1有四个,则一定能插进去

 

#include<bits/stdc++.h>
using namespace std;
map<int,int> s;

int main(){
	int n,x;
	int maxx=0,y=-1;
	cin>>n;
	for(int i=0;i<n;++i){
		cin>>x;
		s[x]++;
		if(s[x]>maxx){
			maxx=s[x];
			y=x;
		}
	}
	if(maxx==n) cout<<"-1";
	else cout<<y;
	return 0;
} 

然后我自己写了个二分加set维护所有的情况~(想了好久呢~),首先长度是有序递增的可以二分,二分用一个set<ll>st[100007] 处理所有出现的次数的数。nice~ 说实话我当时还傻傻的好奇别人的二分是咋判断的呢~

//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
typedef  long long ll;
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
#define per(i,j,n) for(ll i=j;i>=n;i--)
#define pr(x) printf("%lld\n",x) 
typedef unsigned long long ull;
typedef unsigned int us;
const ll INF=1e18+7;const double eps=1e-8,pi=acos(-1);
const ll mod=1000000007;
const ll maxx=1e6+700;
inline bool read(ll &num){char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m;
ll a[maxx];
ll p;
ll vis[100007];
set<ll>st[100007];
ll judge(ll x)
{
	memset(vis,0,sizeof(vis));
	for(int i=0;i<=n;i++)
	st[i].clear();
	ll maxl=0;
	ll num;
	rep(i,1,x)
	{
		vis[a[i]]++;
		num=vis[a[i]]; 
		st[num].insert(a[i]);
		maxl=max(maxl,num);
		st[num-1].erase(a[i]);
	}
	if(st[maxl].size()>=2)
	{
		p=*st[maxl].begin();
		return 1;
	}
	rep(i,x+1,n)
	{
		vis[a[i-x]]--;
		num=vis[a[i-x]];
		st[num].insert(a[i-x]);
		st[num+1].erase(a[i-x]);
		if(num+1==maxl && st[num+1].empty())
		maxl--;
		
		vis[a[i]]++;
		num=vis[a[i]]; 
		st[num].insert(a[i]);
		maxl=max(maxl,num);
		st[num-1].erase(a[i]);
		
		if(st[maxl].size()>=2)
		{
			p=*st[maxl].begin();
			return 1;
		}	
	}
	return 0;
}
int main()
{
    ll t;
	cin>>n;
	rep(i,1,n) read(a[i]);
	int flag=0;
	rep(i,2,n)
	{
		if(a[i]!=a[1]) flag=1;
	}
	if(flag==0) {
		printf("-1\n");	
		return 0;
	}
	ll l=1,r=n;
	ll ans=0;
	ll len=0;
	while(l<=r)
	{
		ll mid=(l+r)>>1;
		if(judge(mid))
		{
			if(mid>len)
			{
				ans=p;
				len=mid;
			}
			l=mid+1;
		}
		else r=mid-1;
	}
	printf("%lld\n",ans);
	return 0;
}

 

链接:https://ac.nowcoder.com/acm/contest/11290/D
来源:牛客网
 

小g有很多士兵玩具,他喜欢将这些玩具放成一排,每个玩具有它的类型编号,有时他会将其中一段位置连续的玩具拿出来“击♂剑”。但是他喜欢均衡,如果他选出来的玩具中类型出现次数最多的玩具不唯一,那么他就会很开心。比如说[1,1,2,2,3],出现次数最多的是类型1和类型2的玩具,他会很开心。


与此同时,他希望能够选出令他高兴的这一段的长度越长越好,他会选那些最长符合条件的连续段,这样的段可能不止一个,其中每一段都有它的出现次数最多的玩具类型,你只需要输出他选择的任意一段中的出现次数最多的玩具类型中任意的一种。

输入描述:

 

第一行一个数n(1≤n≤105)n(1\le n\le 10^5)n(1≤n≤105),代表玩具的个数。

第二行有nnn个数,每个数ai(1≤ai≤n)a_i(1\le a_i\le n)ai​(1≤ai​≤n),代表着每个玩具的类型。

输出描述:

输出一个数,它得满足题目条件,如果找不到输出-1。

示例1

输入

复制5 1 1 3 2 2

5
1 1 3 2 2

输出

复制1

1

说明

 

[1,3],[3,2],[1,3,2]和[1,1,3,2,2]都是符合条件的连续段,但是其中长度最长的是[1,1,3,2,2]的情况,其中1和2出现次数都最多,所以可以输出1或2。

示例2

输入

复制3 1 1 1

3
1 1 1

输出

复制-1

-1

说明

 

找不着一个符合条件的子串,输出-1。

示例3

输入

复制5 2 1 1 1 3

5
2 1 1 1 3

输出

复制3

3

说明

 

[2,1],[1,3]都是符合条件的连续段,两个都是长度最长的,第一段中1和2出现次数都最多,第二段中2和3出现次数都最多。所以可以输出1或2或3。

 

 

F 反复读密码锁 (其实就是个小规律,如果n的二进制的长度和二进制0的个数同奇偶,则0,否则为1)

//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
typedef  long long ll;
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
#define per(i,j,n) for(ll i=j;i>=n;i--)
#define pr(x) printf("%lld\n",x) 
typedef unsigned long long ull;
typedef unsigned int us;
const ll INF=1e18+7;const double eps=1e-8,pi=acos(-1);
const ll mod=1000000007;
const ll maxx=1e6+700;
inline bool read(ll &num){char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m;
ll a[maxx];
int main()
{
    ll t;
	cin>>t;
	while(t--)
	{
		read(n);
		ll len=0;
		ll num=0;
		while(n)
		{
			if(n%2==0) num++;
			len++;
			n/=2;
		}
		if(len%2!=num%2) printf("1\n");
		else printf("0\n");
	}
	return 0;
}

H松果痰抖闪电鞭  每五个一循环,打个表就找到规律了

//#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
typedef  long long ll;
using namespace std;
#define rep(i,j,n) for(ll i=j;i<=n;i++)
#define per(i,j,n) for(ll i=j;i>=n;i--)
#define pr(x) printf("%lld\n",x) 
typedef unsigned long long ull;
typedef unsigned int us;
const ll INF=1e18+7;const double eps=1e-8,pi=acos(-1);
const ll mod=1000000007;
const ll maxx=1e6+700;
inline bool read(ll &num){char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m;
double num[maxx];
int main()
{
    ll t;
	double a,b;
	ll k;
	cin>>a>>b>>k;

	num[1]=a;
	num[2]=b;
	
	rep(i,3,8)
	{
		num[i]=(1.0+num[i-1])/num[i-2];
	}
	
	//printf("%.5f\n%.5f\n",a,b);
	
	ll p=k%5;
	if(p==0) p=5;
	printf("%.10lf\n",num[p]);
	
	return 0;
}

J ACM基地招新大会

找左边第一个比他大的会用栈,两个就不会了呢咋,自己写了个假算法T%95,依然是考虑栈,但要记录的是左侧第一个比他大的位置,找到之后利用前面已经有的位置继续往前跑就行,大题复杂度8*n左右吧。

#include <iostream>
#include <stack>
 
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100005;
int a[maxn], n, m = -1, L[maxn], ans[maxn];
 
stack<int> s;
int main() {
    scanf("%d", &n);
    s.push(0);
    a[0] = inf;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        while(a[s.top()] <= a[i]) s.pop();
        L[i] = s.top();
        if(L[i] == 0) {
            printf("1\n");
            ans[i] = 1;
        } else {
            int k = (a[i] >= a[i - 1] && L[i] == L[i - 1]) ? ans[i - 1] - 1 : L[i] - 1;
            while(a[k] <= a[i]) k--;
            printf("%d\n", k + 1);
            ans[i] = k + 1;
        }
        s.push(i);
    }
    return 0;
}

 

J不讲武德: 方法太多了,随便搞都行。

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值