SCAU2021春季个人排位赛第四场 (部分题解)

预设应该有:
简单题:AD
中等题:BCF
较难题:EG
A:二分
B:状压DP
C:最短路+二分
D:单调栈
E:后缀数组/后缀自动机
F:贪心+堆
G:2-SAT

状压不会,最短路有些许忘记,先写了其中已经改了的题解先。

 

A题

CodeForces - 371C

Polycarpus loves hamburgers very much. He especially adores the hamburgers he makes with his own hands. Polycarpus thinks that there are only three decent ingredients to make hamburgers from: a bread, sausage and cheese. He writes down the recipe of his favorite "Le Hamburger de Polycarpus" as a string of letters 'B' (bread), 'S' (sausage) и 'C' (cheese). The ingredients in the recipe go from bottom to top, for example, recipe "ВSCBS" represents the hamburger where the ingredients go from bottom to top as bread, sausage, cheese, bread and sausage again.

Polycarpus has nb pieces of bread, ns pieces of sausage and nc pieces of cheese in the kitchen. Besides, the shop nearby has all three ingredients, the prices are pb rubles for a piece of bread, ps for a piece of sausage and pc for a piece of cheese.

Polycarpus has r rubles and he is ready to shop on them. What maximum number of hamburgers can he cook? You can assume that Polycarpus cannot break or slice any of the pieces of bread, sausage or cheese. Besides, the shop has an unlimited number of pieces of each ingredient.

Input

The first line of the input contains a non-empty string that describes the recipe of "Le Hamburger de Polycarpus". The length of the string doesn't exceed 100, the string contains only letters 'B' (uppercase English B), 'S' (uppercase English S) and 'C' (uppercase English C).

The second line contains three integers nbnsnc (1 ≤ nb, ns, nc ≤ 100) — the number of the pieces of bread, sausage and cheese on Polycarpus' kitchen. The third line contains three integers pbpspc (1 ≤ pb, ps, pc ≤ 100) — the price of one piece of bread, sausage and cheese in the shop. Finally, the fourth line contains integer r (1 ≤ r ≤ 1012) — the number of rubles Polycarpus has.

Please, do not write the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64d specifier.

Output

Print the maximum number of hamburgers Polycarpus can make. If he can't make any hamburger, print 0.

Examples

Input

BBBSSC
6 4 1
1 2 3
4

Output

2

Input

BBC
1 10 1
1 10 1
21

Output

7

Input

BSC
1 1 1
1 1 3
1000000000000

Output

200000000001

 

题意:做一个汉堡需要B、S、C三种搭配。搭配的方式很多种,但是只想要一种规定的搭配。目前厨房里拥有一定的B、S、C,分别为nb、ns、nc。其次你有一定的钱,可以去商店里买来B、S、C,分别以pb,ps,pc的价格。请问你最多能够做多少个汉堡。

 

题解:

我们采取一种比较贪心的思路,先用完厨房里拥有的B、S、C,然后再出去商店一套一套地买汉堡配料,看看能够买多少份。

 

对的,这道题我挺晚做出来,还是一开始对题意有一丝丝理解错误,然后后面一套一套买汉堡那里没有处理好。

#include 
#include 
#include 

using namespace std;

string st;
long long  len,B,S,C,ans,ans1,ans2;
long long  bi,si,ci;
long long  pb,ps,pc;
long long  mon;
long long mon_ham;
long long num_ham;

void read_in()
{
    cin>>st;len=st.size();
    for(int i=0;i>bi>>si>>ci>>pb>>ps>>pc>>mon;
    mon_ham=S*ps+B*pb+C*pc;
}

long long  take_ham()
{
    long long  b=100000,s=100000,c=100000;
    if(B!=0)  b=bi/B;
    if(S!=0)  s=si/S;
    if(C!=0)  c=ci/C;
    long long  ham=min(min(b,s),c);
    bi-=B*ham;si-=S*ham;ci-=C*ham;
    return ham;
}

bool judge_it()
{
    long long cut=0;
    if(B>bi && B!=0)
        cut+=pb*(B-bi);
    if(S>si && S!=0)
        cut+=ps*(S-si);
    if(C>ci && C!=0)
        cut+=pc*(C-ci);
    if(cut==mon_ham)
        return false;
    if(cut<=mon)
        return true;
    return false;
}

void buy_()
{
    if(B>bi)
    {
        int buy_b=B-bi;
        if(mon>=buy_b*pb)
        {
            bi+=buy_b;
            mon-=buy_b*pb;
        }
    }
    if(S>si)
    {
        int buy_s=S-si;
        if(mon>=buy_s*ps)
        {
            si+=buy_s;
            mon-=buy_s*ps;
        }

    }
    if(C>ci)
    {
        int buy_c=C-ci;
        if(mon>=buy_c*pc)
        {
            ci+=buy_c;
            mon-=buy_c*pc;
        }
    }
    return ;
}

void buy_all()
{
    long long mon_ham=S*ps+B*pb+C*pc;
    long long num_ham=mon/mon_ham; 
    ans+=num_ham;
    mon=mon%mon_ham;
}

int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    read_in();
    ans+=take_ham();
    while(judge_it())
    {
        buy_();
        ans+=take_ham();
    }
    buy_all();
    cout<

 

C题

黑暗爆炸 - 1614

 

Description

FarmerJohn打算将电话线引到自己的农场,但电信公司并不打算为他提供免费服务。于是,FJ必须为此向电信公司

支付一定的费用。FJ的农场周围分布着N(1<=N<=1,000)根按1..N顺次编号的废弃的电话线杆,任意两根电话线杆间

都没有电话线相连。一共P(1<=P<=10,000)对电话线杆间可以拉电话线,其余的那些由于隔得太远而无法被连接。

第i对电话线杆的两个端点分别为A_i、B_i,它们间的距离为L_i(1<=L_i<=1,000,000)。数据中保证每对{A_i,B_i

}最多只出现1次。编号为1的电话线杆已经接入了全国的电话网络,整个农场的电话线全都连到了编号为N的电话线

杆上。也就是说,FJ的任务仅仅是找一条将1号和N号电话线杆连起来的路径,其余的电话线杆并不一定要连入电话

网络。经过谈判,电信公司最终同意免费为FJ连结K(0<=K

需要为它们付的费用,等于其中最长的电话线的长度(每根电话线仅连结一对电话线杆)。如果需要连结的电话线

杆不超过K对,那么FJ的总支出为0。请你计算一下,FJ最少需要在电话线上花多少钱。

Input

* 第1行: 3个用空格隔开的整数:N,P,以及K

* 第2..P+1行: 第i+1行为3个用空格隔开的整数:A_i,B_i,L_i

Output

* 第1行: 输出1个整数,为FJ在这项工程上的最小支出。

如果任务不可能完成, 输出-1

Sample Input

5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6
输入说明:
一共有5根废弃的电话线杆。电话线杆1不能直接与电话线杆4、5相连。电话
线杆5不能直接与电话线杆1、3相连。其余所有电话线杆间均可拉电话线。电信
公司可以免费为FJ连结一对电话线杆。

Sample Output

4
输出说明:
FJ选择如下的连结方案:1->3;3->2;2->5,这3对电话线杆间需要的
电话线的长度分别为4、3、9。FJ让电信公司提供那条长度为9的电话线,于是,
他所需要购买的电话线的最大长度为4。

Hint

Source

Silver

 

题意:找出从1到n的最短路之中,第k-1大的边。

以后看到这种求最小中的最大,尝试想想二分才行。现在几乎都不会想到二分。

这里用二分,把大于mid的边设为1,然后小于mid的边设为0。跑一遍最短路,看看到点n的时候距离为多少,既是最短路里的大于mid的边有k条,妙呀。

到达不了的情况就是根本去不了n,如果去的了n点的话那就肯定是有答案的。

代码:

#include
#include
#include
#include
#include

using namespace std;

const int INF=0x3f3f3f3f;
int n,m,k,l,r,mid,ans=-1;
int pi,p[1005],to[20005],nex[20005],cost[20005];
int val[1005];
bool vis[1005];
queueq;

void read_into(int u,int v,int c)
{
	pi++; nex[pi]=p[u]; p[u]=pi; to[pi]=v; cost[pi]=c;
}

void read_in()
{
	ios::sync_with_stdio(false),cin.tie(0);
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++)
	{
		int u,v,c;
		cin>>u>>v>>c;
		read_into(u,v,c);
		read_into(v,u,c);
		r=max(r,c);
	}
}

bool judge_it(int t)
{
	for(int i=1;i<=n;i++)
	  val[i]=INF,vis[i]=false;
	while(!q.empty())
	  q.pop();
	q.push(1); vis[1]=true; val[1]=0;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		vis[u]=false;
		for(int i=p[u],v=to[i];i;i=nex[i],v=to[i])
		{
			if(val[v] > val[u] + (cost[i] > t))
			{
				val[v]=val[u]+ (cost[i]>t);
				if(!vis[v])
				{
					vis[v]=true;
					q.push(v);
				}
			}
		}
	}
	if(val[n] > k)
	  return 0;
	return 1;
}

void work()
{
	while(l<=r)
	{
		mid=(l+r)/2;
		if(judge_it(mid))
		{
			r=mid-1;
			ans=mid;
		}
		else
		  l=mid+1;
		if(val[n]>1000000)
		  break;
	}
	cout<

 

 

D题

UVA - 1619 

Description

Bill is developing a new mathematical theory for human emotions. His recent investigations are dedicated to studying how good or bad days influent people’s memories about some period of life. A new idea Bill has recently developed assigns a non-negative integer value to each day of human life. Bill calls this value the emotional value of the day. The greater the emotional value is, the better the day was. Bill suggests that the value of some period of human life is proportional to the sum of the emotional values of the days in the given period, multiplied by the smallest emotional value of the day in it. This schema reflects that good on average period can be greatly spoiled by one very bad day. Now Bill is planning to investigate his own life and find the period of his life that had the greatest value. Help him to do so.

Input
The input will contain several test cases, each of them as described below. Consecutive test cases are separated by a single blank line.
The first line of the input file contains n — the number of days of Bill’s life he is planning to
investigate (1 ≤ n ≤ 100000). The rest of the file contains n integer numbers a1, a2, . . . , an ranging
from 0 to 106 — the emotional values of the days. Numbers are separated by spaces and/or line breaks.

Output
For each test case, the output must follow the description below. The outputs of two consecutive caseswill be separated by a blank line.
On the first line of the output file print the greatest value of some period of Bill’s life.
On the second line print two numbers l and r such that the period from l-th to r-th day of Bill’s
life (inclusive) has the greatest possible value. If there are multiple periods with the greatest possible value, then print any one of them.

Sample Input
6
3 1 6 4 5 2
1
2
Sample Output
60
3 5
 

题意:

找出一个区间[L,R],有[L,R]中的最小值a使得a*sum[L,R]最大。

 

题解:

这题,怎么说,寒假做过,单调栈模板题,但是当时没有做出来,这次也是。

先说说思路吧,挺简单的,假设我们以i为最小值,那么往左找第一个小于i的数为左边界,右边第一个比他小的数为右边界。这样子就可以找出了n个区间了,然后利用前缀和一个一个枚举。

主要还是在找区间的时候用单调栈,使其时间复杂度为O(n)。

问题就是,可能我就是写单调栈写炸了。

我想只进行一遍单调栈,就把左边第一小和右边第一小找到。但是总是WA。

以后就不要这么贪心了,还是老老实实分开两次单调栈。一次单调栈找一边的第一个出现最小值。

 

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 


using namespace std;

int n;
long long a[1000005],sum[1000005];
int l[1000005],r[1000005];

void read()
{
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);//cin>>a[i];
    for(int i=1;i<=n;i++)
        sum[i]=sum[i-1]+a[i];
}

void build_stack()
{
	l[0]=0;a[0]=-1;
    stack sta1;
    sta1.push(0);
    for(int i=1;i<=n;++i)
    {
    	while(a[sta1.top()]>=a[i])
    	  sta1.pop();
    	l[i]=sta1.top()+1;
    	sta1.push(i);
	}
	a[n+1]=-1;r[n+1]=n+1;
	stack sta2;
	sta2.push(n+1);
	for(int i=n;i>=1;--i)
	{
		while(a[sta2.top()]>=a[i])
		  sta2.pop();
		r[i]=sta2.top()-1;
		sta2.push(i);
	}
}

void work()
{
    long long ans=0;
	int L=1,R=1;
    for(int i=1;i<=n;++i)
    {
    	long long  tmp=(sum[r[i]]-sum[l[i]-1]) * a[i];
        if(tmp>ans || (tmp==ans && R-L>r[i]-l[i]))
        {
            ans=tmp;
            L=l[i];R=r[i];
        }
    }
    //cout<>n
    {
        if(tim!=0)
          cout<<'\n';//printf("\n");
        tim++;
		read();
        build_stack();        
        work();

    }

    return 0;
}

 

你可能感兴趣的:(题解)