2022牛客暑期多校训练营(第一场)补题

I Chiitoitsu

题意

最开始有13张牌,相同的牌最多出现两张。每次摸一张牌,如果实现有七对相同的牌即结束;否则从自己的牌中选一张丢掉。求在最优策略下,结束的预期回合数。

思路

因为最开始相同的牌最多出现两张,所以最优策略是如果后摸到的牌可以与现有的牌构成一对就留下,丢弃现有牌中无法与其他牌构成一对的牌;如果后摸到的牌不能与现有的牌构成一对,就将它丢掉。

求期望dp,令 f(s,r) 表示当前手牌中有 s 张单牌且牌堆中剩余 r 张牌时构成七对牌的期望轮数,则有: 当s=1时,f(s,r)=1+(r-3)/r*f(1,r-1);当s>1时,f(s,r)=1+3*s/r*f(s-2,r-1)+(r-3*s)/r*f(s,r-1)。

对于给定的初始手牌,设其单牌数量为 s0,则 f(s0,136−13) 即为答案。

代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <map>
#define int long long
using namespace std;

char s[200005];
int dp[20][200];
map<string,int> mp;
int inf=1e9+7;

int pow(int x,int n){
    int res=1;
    while(n){
        if(n%2) 
			res=x*res%inf;
        x=x*x%inf;
        n/=2;
    }
    return res;
}
void init(){
    for(int i=1;i<=13;i+=2)
        for(int j=1;j<=123;j++){
            if(i==1)
                dp[i][j]=(1+((j-3)*pow(j,inf-2)%inf)*dp[i][j-1])%inf;
            else
                dp[i][j]=(1+(i*3*pow(j,inf-2)%inf)*dp[i-2][j-1]%inf+((j-3*i)*pow(j,inf-2)%inf)*dp[i][j-1]%inf)%inf;
        }
}

signed main(){
	ios::sync_with_stdio(false);
	
    int t;
    cin>>t;
    init();
    int i,j,k;
    int op=0;
    string s1;
    while(t--){
        op++;
        cin>>s+1;
        cout<<"Case #"<<op<<": ";
        mp.clear();
        for(i=2;i<=26;i+=2){
            s1="";
            s1+=s[i-1];
            s1+=s[i];
            mp[s1]++;
        }
        int cnt=0;
        for(auto u:mp){
            if(u.second==1)
                cnt++;
        }
        cout<<dp[cnt][123]<<endl;
    }
}

A  Villages: Landlines

题意

数轴上有一个发电站与n−1个建筑物,发电站和建筑物必须通过电力塔连接,如果电力塔与发电站的距离小于发电站的半径范围,则不需要电线;如果电力塔与建筑物的距离小于建筑物半径,则不需要电线;如果电力塔与它们的距离大于它们相应的半径就需要距离差的电线。

思路

个人感觉这个题目较难理解,但通过示例画图可以更好地理解

本题是区间合并问题,先算出发电站和建筑物各自的范围,通过sort排序,使区间整体从左到右排好,再进行遍历,寻找没有区间覆盖的地方。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct node
{
	int x;
	int r;
	int l;
	int you;
}pos[200005];
bool cmp(node a,node b)
{
	if(a.l!=b.l)
	return a.l<b.l;
	return a.you<b.you;
}
int main()
{
	int n;
	cin>>n;
	cin>>pos[0].x>>pos[0].r;
	pos[0].l=pos[0].x-pos[0].r;
	pos[0].you=pos[0].x+pos[0].r;
	int i,j;
	for(i=1;i<n;i++)
	{
		cin>>pos[i].x>>pos[i].r;
		pos[i].l=pos[i].x-pos[i].r;
		pos[i].you=pos[i].x+pos[i].r;
	}
	sort(pos,pos+n,cmp);
	long long sum=0;
	int biaol=pos[0].l;
	int biaor=pos[0].you;
	for(i=1;i<n;i++)
	{
		if(pos[i].l>biaor)
		{
			//cout<<biaor<<" "<<pos[i].l<<" "<<i<<endl;
			sum+=pos[i].l-biaor;
			biaor=pos[i].you;
		}
		else
		{
			biaor=max(pos[i].you,biaor);
			//cout<<pos[i].you<<" "<<biaor<<endl;
		}
	}
	cout<<sum;
	
	
	
	
	return 0;
}

D  Lexicographical Maximum

题意

给定n,将 1, 2, . . . , n 视为不含前导零的字符串 求这些字符串中字典序最大的字符串

思路

答案除去最后一位,其余位均为 9 。如果n除去最后一位,其余为均为 9 ,则答案即为 n ;若不然则答案为 |n| − 1 个 9

代码

#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;

int main()
{
	string s;
	cin>>s;
	int i,j;
	int op=-1;
	for(i=0;s[i+1]!=0;i++)
	{
		if(s[i]!='9')
			op=i;
		cout<<"9";
	}
	
	if(op==-1)
		cout<<s[i];
	
	
	return 0;
 } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值