2021.3.21校排位赛(待续



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


A

CodeForces 371C Hamburgers

Time limit1000 ms
Memory limit262144 kB

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 nb, ns, nc (1 ≤ nb, ns, nc ≤ 100) — the number of the pieces of bread, sausage and cheese on Polycarpus’ kitchen. The third line contains three integers pb, ps, pc (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.

输入:
样例1
BBBSSC
6 4 1
1 2 3
4

样例2
BBC
1 10 1
1 10 1
21

样例3
BSC
1 1 1
1 1 3
1000000000000

输出:
样例1
2

样例2
7

样例3
200000000001

题目大意: 给定每个汉堡所需要的三种材料b,s,c的数量,已知自己手头b,s,c的数量和b,s,c的单价,以及手头的零钱,问最多买多少个汉堡?

思路:核心:二分
想法一:贪心地先补掉“拖累整体”的那种材料,然后一个一个汉堡地去补。这样就成了模拟题,考虑的东西的太多了,蒟蒻这就不写了QAQ

正解:二分汉堡数
注意点:开longlong还有二分右界要大于1e12+100,因为单价≥1且每种已有的材料数≤100。

//二分汉堡数量
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define int long long
using namespace std;
typedef long long ll;
int have[5];
int price[5];
int num[5];
ll mon;
bool check(ll mid)
{
    
    
    ll temp = mon;
    _for(i,1,3)
    {
    
    
        if( have[i] < num[i] * mid)
        {
    
    
            temp -= price[i] * ( num[i] * mid - have[i] );
        }
        if( temp <0 ) return false;//钱不够了,直接返回
    }
    return true;
}
signed main()
{
    
    
    IOS;
    string s;
    cin>>s;
    _for(i,0,s.size()-1)
    {
    
    
        if( s[i] == 'B') num[1]++;
        if( s[i] == 'S') num[2]++;
        if( s[i] == 'C') num[3]++;
    }

    _for(i,1,3) cin>>have[i];

    _for(i,1,3) cin>>price[i];

    cin>>mon;
    ll l = 0, r = 1e12+1500;//右界往1e12右边开一点
    while( l<=r )
    {
    
    
        int mid = ( l+r )>>1;
        if( check (mid) ) l = mid +1;
        else r = mid-1;
    }

    cout<<l-1<<endl;;
}

B

方格取数

Time limit5000 ms
Memory limit32768 kB

给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。

Input
包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)

Output
对于每个测试实例,输出可能取得的最大的和

输入:
3
75 15 21
75 15 28
34 70 5

输出:
188

思路: 核心:状压dp
思路1,dfs,每个位置两种状态,当n=20时,复杂度O(2^400),显然tle,不可取。

正解:考虑先删去行里相邻的情况,当n=20时,行状态数最多17711,总状态17711 * 17711 *19接近10^9,时限给的5s,可以过。
dp[i][j]表示第i行是j种状态时,前i行和的最大值,sum[i][j]表示第i行取第j种状态时,行的取值和。
当上下两行相与不为1时,满足转移方程dp[i][j] = max( dp[i][j],dp[i-1][j] + sum[i-1][上一行的某状态]) 。

//状压dp
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <map>
#include <queue>
//#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)

using namespace std;
typedef long long ll;

const int N = 17711;
int dp[25][N+10];//第j种状态时前i行值的和
int sum[25][N+10];//第i行第j种状态的最大值
int state[N+10];
int mp[25][25];
int cnt=0;
int n;
void cal(int x, int y)//第y种状态时第x行的和
{
    
    
    _for(j,0,n-1)
    {
    
    
        if( (state[y]>>j) & 1 )
        {
    
    
            sum[x][y] += mp[x][n-j];
        }
    }
}
int main()
{
    
    
    IOS;
    while(cin>>n)
    {
    
    
        memset(dp,0,sizeof(dp));
        memset(sum,0,sizeof(sum));
        cnt=0;
        int cnt=0;
        //算行里状态数
        for(int i=0 ;i<(1<<n) ;i++)
        {
    
    
            if(!(i & (i<<1)) )//不相邻
            {
    
    
                state[++cnt] = i;
            }
        }
        //算行状态和
        _for(i,1,n)
            _for(j,1,n) cin>>mp[i][j];

         //算每种状态的行取值和
        _for(i,1,n)
        {
    
    
            _for(j,1,cnt)
            {
    
    
                cal(i,j);
            }
        }

        _for(i,1,cnt) dp[1][i] = sum[1][i];

        _for(i,2,n)//从第二行开始枚举
        {
    
    
            _for(j,1,cnt)//本行状态
            {
    
    
                _for(k,1,cnt)//上一行状态
                {
    
    
                    if( !( state[j] & state[k] ) )//上下不相邻
                    dp[i][j] = max(dp[i][j] , sum[i][j] + dp[i-1][k]);
                }
            }
        }
        ll maxn=0;
        _for(i,1,cnt)
        maxn = max(maxn, 1ll * dp[n][i]);
        cout<<maxn<<endl;
    }
}

C

Telephone Lines架设电话线 dboj - 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<N)对由FJ指定的电话线杆。对于此外的那些电话线,FJ
需要为它们付的费用,等于其中最长的电话线的长度(每根电话线仅连结一对电话线杆)。如果需要连结的电话线
杆不超过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

输入:
5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6

输出:
4

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

思路: 二分+最短路
二分找最短路中第k+1条路的大小,显然满足单调性,因为如果(假设的第k+1条路的大小越大),最短路中连更多边的可能性更高,可行性更高。(不必纠结于单调性,显然越小越好= =)
假设第k+1条边长d,大于d的边花费为1,小于等于d的边花费为0,跑一下最短路,判断最后花费是否大于k即可。

//二分+最短路
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)

using namespace std;
typedef long long ll;

const int N = 1000+10;

int head[N];
int tot = 0;
int dis[N];
int n,p,k;
int v[N];
vector <int > vec;
struct ty
{
    
    
    int t,next;
    int cost,val;
    bool operator < (const  ty &b) const
    {
    
    
        return val > b.val;
    }
}edge[N*20];
priority_queue <ty > q;
void addedge(int x, int y, int z)
{
    
    
    edge[++tot].t =  y;
    edge[tot].next = head[x];
    edge[tot].val = z;
    head[x] = tot;
}
int dij( int p) //最短路
{
    
    
    memset(dis,0x3f,sizeof(dis));
    memset(v,0,sizeof(v));
    ty t1;
    t1.t = 1;
    t1.val = 0;
    dis[1] = 0;
    q.push( t1);
    while( !q.empty() )
    {
    
    
        ty x = q.top();
        q.pop();
        if( v[x.t] ) continue;
        v[x.t] = 1;
        for(int i=head[x.t] ;i!=-1 ;i=edge[i].next )
        {
    
    
            int y = edge[i].t;
            int v = edge[i].val;
            int cost = (p < v );
            if( dis[x.t] + cost < dis[y] )
            {
    
    

                dis[y] = dis[x.t] + cost;
                ty t2;
                t2.t = y;
                t2.val = dis[y];
                q.push(t2);
            }
        }
    }
    return dis[n] > k;//需要免费的部分是否大于 k,大于则边选小了
}
int main()
{
    
    
    IOS;
    memset(head,-1,sizeof(head));
    cin>>n>>p>>k;
    _for(i,1,p)
    {
    
    
        int x,y,z;
        cin>>x>>y>>z;
        addedge(x ,y ,z);
        addedge(y, x,z);
        vec.push_back(z);
    }
    sort(vec.begin() , vec.end());//因为在已知边里二分,需要对已知边排序
    //二分求第k+1条路
    int l = 0,r=vec.size()-1;
     while( l<=r )
     {
    
    
        int mid=( l+r) >>1;
        if( dij(vec[mid]) ) l = mid+1;
        else  r = mid-1;
     }
    if(l>vec.size()-1) cout<<-1<<endl;
    else if( r<0)   cout<<0<<endl;
    else cout<<vec[l]<<endl;
}

D

Feel Good POJ-2796

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 daywas. 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 first line of the input contains n - the number of days of Bill’s life he is planning to investigate(1 <= n <= 100 000). 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
Print the greatest value of some period of Bill’s life in the first line. And 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.
输入:
6
3 1 6 4 5 2

输出:
60
3 5
题目大意: 给定一串数,求某个区间使得区间和 乘上区间 权值最小的数最大
思路: 核心:单调栈 O(n)
对每个数求它的左右边界,边界指比它还小的数,求左右边界各用一次单调递增栈,维护权值递增,记录边界。
最后记得清空栈内元素,此时栈内是单调不减的,所以栈内元素的右边界赋为n+1,左边界赋为0.
最后用前缀和再扫一遍数组即可。

//单调栈
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <map>
#include <queue>
//#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)

using namespace std;
typedef long long ll;

const int N = 100000+10;
int l[N];//a[i]的左边界
int r[N];//a[i]的右边界
ll sum[N];//前缀和
struct ty
{
    
    
    int index;
    int val;
}a[N];
vector < ty > sta;//单调递增栈
int main()
{
    
    
    IOS;
    int n;
    while( cin>>n )
    {
    
    
        memset(sum,0,sizeof(sum));
        _for(i,1,n)
        {
    
    
            cin>>a[i].val;
            a[i].index = i;
            sum[i] = sum[i-1] + a[i].val;
        }
        //处理右界
        _for(i,1,n)
        {
    
    
             if( sta.empty() || a[i].val >= sta.back().val )
             {
    
    
                 sta.push_back( a[i] );
             }
             else
             {
    
    
                 while( !sta.empty() && sta.back().val > a[i].val )
                 {
    
    
                     ty x = sta.back();
                     r[x.index] = a[i].index;
                     sta.pop_back();
                 }
                 sta.push_back(a[i]);
             }
        }
        while( !sta.empty() )
        {
    
    
            ty x = sta.back();
    //        cout<<x.index<<endl;
            r[x.index] = n+1;
            sta.pop_back();
        }
        //处理左界
        for(int i=n ;i>=1 ;i--)
        {
    
    
             if( sta.empty() || a[i].val >= sta.back().val )
             {
    
    
                 sta.push_back( a[i] );
             }
             else
             {
    
    
                 while( !sta.empty() && sta.back().val > a[i].val )
                 {
    
    
                     ty x = sta.back();
                     l[x.index] = a[i].index;
                     sta.pop_back();
                 }
                 sta.push_back(a[i]);
             }
        }
        while( !sta.empty() )
        {
    
    
            ty x = sta.back();
            l[x.index] = 0;
            sta.pop_back();
        }

        //求值
        ll maxn = 0;
        int l2=1e7,r2=1e7;
        _for(i,1,n)
        {
    
    
            int zuo = l[i];
            int you = r[i];
            ll temp = a[i].val * (sum[you-1] - sum[zuo] );
            if( temp > maxn)
            {
    
    
                maxn = temp;
                l2 = l[i];
                r2 = r[i];
            }
        }
        if( maxn == 0)
        {
    
    
            cout<<0<<endl;
            cout<<"1 1"<<endl;
        }
        else
        {
    
    
            cout<<maxn<<endl;
            cout<<l2+1<<" "<<r2-1<<endl;
        }
    }
}

F

Stall Reservations POJ - 3190

Time limit1000 ms
Memory limit65536 kB

Oh those picky N (1 <= N <= 50,000) cows! They are so picky that each one will only be milked over some precise time interval A…B (1 <= A <= B <= 1,000,000), which includes both times A and B. Obviously, FJ must create a reservation system to determine which stall each cow can be assigned for her milking time. Of course, no cow will share such a private moment with other cows.

Help FJ by determining:
The minimum number of stalls required in the barn so that each cow can have her private milking period
An assignment of cows to these stalls over time
Many answers are correct for each test dataset; a program will grade your answer.

Input
Line 1: A single integer, N

Lines 2…N+1: Line i+1 describes cow i’s milking interval with two space-separated integers.

Output
Line 1: The minimum number of stalls the barn must have.

Lines 2…N+1: Line i+1 describes the stall to which cow i will be assigned for her milking period.
输入:
5
1 10
2 4
3 6
5 8
4 7

输出:
4
1
2
3
2
4

说明
Explanation of the sample:

Here’s a graphical schedule for this output:

Time 1 2 3 4 5 6 7 8 9 10

Stall 1 c1>>>>>>>>>>>>>>>>>>>>>>>>>>>

Stall 2 … c2>>>>>> c4>>>>>>>>> … …

Stall 3 … … c3>>>>>>>>> … … … …

Stall 4 … … … c5>>>>>>>>> … … …
Other outputs using the same number of stalls are possible.

题目大意:有n头牛,每头牛给定一段时间的入棚时间,且每头牛不能和其他牛同时入一个牛棚,问至少需要多少个牛棚,以及每头牛所在的牛棚编号。

思路: 贪心+优先队列
按照牛入棚时间排序,贪心,每头牛入的棚一定是之前有的棚中结束时间最早的,假设入结束时间最早的牛棚不是最优选择,那么入其他牛棚时,牛棚结束时间只可能更晚,导致无法入棚,矛盾。
所以堆维护结束时间最早的牛棚,每头牛判断是否能扔进堆顶,不行就另开牛棚,再维护一下每头牛入的牛棚即可。
(一开始想着是活动安排,按照结束时间排序,没有思路= =

//贪心+优先队列
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <map>
#include <queue>
//#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)

using namespace std;
typedef long long ll;
const int N = 5e4+10;
int fa[N];//每头牛所在的牛棚
struct ty
{
    
    
    int begin,end;
    int index;

}a[N];
struct ty2
{
    
    
    int end,cnt;
    int id;
    bool operator < (const ty2 &b) const
    {
    
    
        //结束时间早的在上面
        return end > b.end;
    }

};
bool cmp(ty a ,ty b)
{
    
    
    return a.begin <b.begin;

}
priority_queue <ty2 > q;

int main()
{
    
    
    IOS;
    int n;
    cin>>n;
    _for(i,1,n)
    {
    
    
        cin>>a[i].begin>>a[i].end;
        a[i].index = i;
    }
    sort(a+1 ,a+1+n ,cmp);//按照入棚时间排序

    ty2 t1;
    t1.end = a[1].end;
    t1.cnt = 1;
    t1.id = 1;
    fa[a[1].index] = 1;
    q.push(t1);
    _for(i,2,n)
    {
    
    
        ty2 x = q.top();
        //符合就更新堆顶
        if( a[i].begin > x.end )
        {
    
    
            q.pop();
            x.end = a[i].end;
            fa[a[i].index] = x.id;
            x.cnt++;
            q.push(x);
        }
        //否则扔进新牛棚
        else
        {
    
    
            ty2 y;
            y.end = a[i].end;
            y.cnt = 1;
            y.id = q.size()+1;
            fa[a[i].index] = y.id;
            q.push(y);
        }
    }
    cout<<q.size()<<endl;

    _for(i,1,n)
    cout<<fa[i]<<endl;
}

总结

我太弱了,学无止境

猜你喜欢

转载自blog.csdn.net/m0_53688600/article/details/115188826
今日推荐