第一次校赛(优先队列)

2019长沙学院暑假集训队第一次校赛

点击  >优先队列<

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

题目描述

给定三个数:x, y, z;

找出一个数v使得:x|v,  y|v,  z|v,

那么v/x+v/y+v/z最小可能是多少?

说明:a|b表示a整除b。

输入描述:

三个整数x,y,z(1≤x,y,z≤1e8)

输出描述:

一个数,表示答案。

示例1

输入

复制

1 2 4

输出

复制

7

防止爆Long long  公式化简

(xy + yz + xz ) * v    /    xyz   式1

  u=(x*y)/gcd(x,y)

  u代入   ->    v=(u*z) / gcd(u,z)

式1 化简为(xy + yz +xz) /gcd(x,y)/gcd(u,z)

#include<bits/stdc++.h>
using namespace std;
  
long long  x,y,z;
int main()
{
      
    long long  a[4];
    cin>>a[0]>>a[1]>>a[2];
    x=a[0];
    y=a[1];
    z=a[2];
    long long res1=a[0]*a[1];
    long long  gccd1=__gcd(a[0],a[1]);
    res1=res1/gccd1;
    long long res2=__gcd(res1,a[2]);
    res1=gccd1;
    cout<<(x*y/res1/res2)+(y*z/res1/res2)+(x*z/res1/res2)<<endl;
}

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

题目描述

有一个字符串num= "0",你有n次操作,每次操作:1 x,在num右边加一个数字字符x,操作:0 x,在num左边加一个数字字符x,每次操作后都要输出新的num转变数字后模1e9+7的值。

输入描述:

 

输出描述:

n行每行一个数字

示例1

输入

复制

10
1 0
1 2
0 0
0 1
0 2
0 1
0 1
1 0
1 0
1 0

输出

复制

0
2
2
10002
210002
1210002
11210002
112100020
121000193
210001923

重点:取模运算 % ,具有可加性   (cs*=10)%mod 不影响正确结果 即在取模环境下  结果不变

#include<bits/stdc++.h> 
#define mod 1000000007
using namespace std;
long long int cs=1;
long long num=0;
int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int x,y;
		cin>>x>>y;
		cs*=10;
		cs=cs%mod;
		if(x==0)
		{
			num+=cs*y;
			num=num%mod;
		}
		else if(x==1)
		{
				num*=10;
				num+=y;
				num=num%mod;				
		}
	    printf("%lld\n",num%mod);
	}
	
}

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

题目描述

有一个n * n的地图,每个格子(i, j)都有权值 ,现在你在(1, 1)起点位置, 每次你可以往下走或者往右走,每走到一个格子就会获得该格子的权值(起点的也算),问你走到终点(n, n)有多少条不同的路径,其路径上的权值总和刚好为2019。答案对1e9 + 7取模

输入描述:

第一行输入一个n(1 <= n <= 100)

接下来n行,每行输入n个数字,第i行j列为 aij(1 <= aij <=2019)

输出描述:

一个数,表示答案。

示例1

输入

复制

2
1 2017
2017 1

输出

复制

2

简单DP  构建三维dp数组dp[i][j][k]  在(i,j) 点 权值和为k 的 路径数

状态转移方程 dp[i][j][k]=dp[i-1][j][ k-a[i][j] ]  +  dp[i][j-1][ k-a[i][j] ]

记忆化搜索 递归  

dp[i][j][k]+=go(i-1,j,k-a[i][j])+go(i,j-1,k-a[i][j]);

;

记忆化递归写法:

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
long long  dp[105][105][2020],dpp[105][105][2020];
int a[105][105];
int n;
int ans=0;
int go(int i,int j,int k)
{
    if(k<0) return 0;
    if(i*j==0)
    {
        return dp[i][j][k]=0;
    }
    if(!dpp[i][j][k])
    {
        dp[i][j][k]+=go(i-1,j,k-a[i][j])+go(i,j-1,k-a[i][j]);
        dp[i][j][k]%=mod;
//      printf("dp[%d][%d][%d]=%d\n",i,j,k,dp[i][j][k]);
        dpp[i][j][k]=1;
    }
    return dp[i][j][k];
     
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    dp[1][1][a[1][1]]=1;
    dpp[1][1][a[1][1]]=1;
     
    printf("%lld\n",go(n,n,2019));
     
 
         
}

递推写法:

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
long long  dp[105][105][2020],dpp[105][105][2020];
int a[105][105];
int n;
int ans=0;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    dp[1][1][a[1][1]]=1;
    dpp[1][1][a[1][1]]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int k=a[i][j];k<=2019;k++)
            {
                dp[i][j][k]+=dp[i-1][j][k-a[i][j]];
                dp[i][j][k]%=mod;
                dp[i][j][k]+=dp[i][j-1][k-a[i][j]];
                dp[i][j][k]%=mod;
            }
        }
    }
     
    printf("%lld\n",dp[n][n][2019]);
     
 
         
}

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

题目描述

给一个长度不超过1e5的字符串s,字符串元素只能是小写字母c, s, u其中的一个,现在定义四元组:[x1, x2, x3, x4] 合法的条件:s[x1] = c 且 s[x2] = c 且 s[x3] = s 且 s[x4] = u,且 x1 < x2 < x3 < x4,现在要求你把s切开成两个子串a, b(a,b不能是空串),求最小的a串合法四元组个数与b串合法四元组个数的差的绝对值

输入描述:

一个字符串s (2 <= |s| <= 1e5)

输出描述:

一个数,表示答案。

示例1

输入

复制

ccsuuccssuu

输出

复制

2

示例2

输入

复制

ccsuccsu

输出

复制

0

左扫描记录当前

C

CC

CCS

CCSU

右扫描记录当前数目

u

SU

CSU

CCSU

最后枚举所有分法 取最小值min(abs(sum1[i]-sum2[i+1],ans)

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
ll dp[5],dpp[5],sum1[100005],sum2[100005];
char a[100005];
int main()
{
	cin>>a;
	int l=strlen(a);
	for(int i=0;i<l;i++)
	{
		
		if(a[i]=='c')
		{
			dp[2]+=dp[1];
			dp[1]++;
		}
		else if(a[i]=='s')
		{
			
			dp[3]+=dp[2];
			
		}
		else if(a[i]=='u')
		{
			dp[4]+=dp[3]; 
		}
		sum1[i]=dp[4];
	}
	for(int i=l-1;i>=0;i--)
	{
		if(a[i]=='u')
		{
			dpp[1]++;
		}
		else if(a[i]=='s')
		{
			dpp[2]+=dpp[1];
			
		}
		else if(a[i]=='c')
		{
			
			dpp[4]+=dpp[3];
			dpp[3]+=dpp[2]; 
		}
		sum2[i]=dpp[4];
	}
	ll ans=1e18;
	for(int i=0;i<l-1;i++)
	{
		ans=min(ans,abs(sum1[i]-sum2[i+1]));
	}
	printf("%lld\n",ans);
}

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

排位赛

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

题目描述

众所周知王者荣耀排位赛可以禁英雄,现在有n个英雄,每对英雄之间有配合度,现在你要选出5个英雄去参加比赛,但是对方能禁止两个英雄,使得你不能选取被禁止的英雄,假设对方采取最优策略禁止英雄,求你选取英雄后所能得到最大的总配合度

输入描述:

第一行输入一个n(7 <= n <= 20)

接下来n行,每行输入n个数字,第i行j列为aij,表示英雄i和英雄j的配合度(0 <= aij <= 1e5)

输出描述:

一个数,表示答案。

示例1

输入

复制

7
0 8 5 1 10 5 9 
8 0 3 5 6 6 2 
5 3 0 2 2 6 3 
1 5 2 0 7 2 5 
10 6 2 7 0 4 3 
5 6 6 2 4 0 2 
9 2 3 5 3 2 0

输出

复制

36

dfs回溯剪枝 枚举 所有情况  因对方最有策略禁英雄 则只能采取min值

#include<bits/stdc++.h>
using namespace std;
int aa[25][25];
int a[25];
int stk[6];
int cnt=0;
int x,y;
	int n;
int ans=1e9,res;
int dfs(int t)
{
	if(cnt==5)
	{
		int sum=0;
		
		for(int i=0;i<4;i++)
		{
			for(int j=i+1;j<5;j++)
			{
				sum+=aa[stk[i]][stk[j]];
			}
		}
		
		res=max(res,sum);
		return 0;
	}
	if(t>n) return 0;
	
	dfs(t+1);
	if(t!=x&&t!=y)
	{
		stk[cnt++]=t;
		dfs(t+1);
//		stk.pop();
		cnt--;
	}
	
	
}
int main()
{

	cin>>n;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			scanf("%d",&aa[i][j]);
		}
	}
	
	for(int i=1;i<n;i++) 
	{
		for(int j=i+1;j<=n;j++)
		{
			res=0;
			x=i;
			y=j;
			dfs(1);
			ans=min(ans,res);
		}
	}
	printf("%d\n",ans);
	
	
}

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

构造B数组

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

题目描述

给一个长度为n的数组a,现在要你构造一个长度为n的数组b,使得数组b的元素总和恰好为m且每个元素最小值不能小于0,且  最小,求出这个最小值

输入描述:

第一行输入两个数n,m (1 <= n, m <= 1e5)

第二行输入n个数表示ai(1 <= ai <= 1e3)

输出描述:

一个数,表示答案

示例1

输入

复制

3 1
1 2 3

输出

复制

21

示例2

输入

复制

3 5
1 1 2

输出

复制

1

点击  >优先队列<

解法:贪心、确保每一次增加 都使得结果增加最小  在优先队列中不断取最小增加的情况不断更新队列

注意!:更新后的结构体未被修改  需要从队中逐个取出进行求和

优先队列 priority_queue

     结构体重载  < 运算符

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
long long sum=0;
struct node
{
	int a;
	int b;
	int v;
	bool operator < (const node &S) const
	{
		return v > S.v;
	}
}num[100005];
priority_queue<node> que;
int n,m;
int ct(int a,int b)
{
	return a*(a-b)*(a-b);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&num[i].a);
		num[i].b=0;
		num[i].v=ct(num[i].a,num[i].b+1)-ct(num[i].a,num[i].b);
		que.push(num[i]);
	}
	for(int i=0;i<m;i++)
	{
		node t=que.top();
		que.pop();
		t.b++;
		t.v=ct(t.a,t.b+1)-ct(t.a,t.b);
		que.push(t);
	}
	
	for(int i=0;i<n;i++)
	{
		node tt=que.top();
		que.pop();
		sum+=ct(tt.a,tt.b);
	}
	cout<<sum<<endl;
	
}
发布了44 篇原创文章 · 获赞 6 · 访问量 1206

猜你喜欢

转载自blog.csdn.net/qq_43868883/article/details/97614407
今日推荐