20190402训练赛

6 篇文章 0 订阅
3 篇文章 0 订阅

Problem A  Patches
1 s, 256 MB

【Description】Carlos is very concerned with the environment. Whenever possible, he tries to use less polluting

means of transport. He recently got a job close to home and is now using his bike to go to work.

Unfortunately, in the route between his home and his job there is a nail factory, and often some

nails fall from their trucks, and end up puncturing Carlos’ bike tires. Therefore he ends up having to

make several patches on the tires of his bike.

To make the repairs, Carlos uses two different types of patches. Both types are as wide as a bike

tire, but differ in length. As the cost of the patch is proportional to its length, Carlos is trying to find

a way to save money, using the least possible length of patches to make the repairs, without cutting

the patches.

The first step in repairing a tire is making a chalk mark on a position of the tire and then writing

down the distances, measured clockwise, of each of the holes in relation to the chalk mark. Each hole

must be completely covered by a patch. Carl~ao would like your help to determine, given the positions

of the holes, the most economic way to make the repair.

【Input】

The input contains two lines. The first line contains four integers N; C; T1 e T2. Integer N indicates

the number of holes in the tire, and C indicates the cirunference length of the tire, in centimeters.

The lengths of the patches in centimeters are given by integers T1 and T2. The second line contains

N integers Fi, representing the distance, in clockwise direction, from the chalk mark to hole i, in

centimeters.

【Output】

Your program must print a single line, containing a single integer, the smallest total length of patches

needed to make all the repairs.

题意:

一个轮胎上破了n个洞,现有两个长度不一样的补丁,要求使用最短长度的补丁补上这n个洞,一个补丁可以一下补很多个洞

 

一开始想贪心,然后就没贪出来...意识到可能要用区间dp,然后就不想写了,,比赛完了补题时才发现也就是个板子题目......

三重循环枚举长度,起点,分割点,然后先判断一下起点到枚举的终点能不能用一个补丁补完,这里得先用小的判断。

然后就剩下的就正常做就好了。

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
int a[1010],n,c,t1,t2,dp[1010][1010];
int main()
{
    while(~scanf("%d%d%d%d",&n,&c,&t1,&t2)){
            if(t1>t2)
            swap(t1,t2);
            memset(a,0,sizeof(a));
            memset(dp,inf,sizeof(dp));
      for(int i=1;i<=n;i++){
        sc(a[i]);
        dp[i][i]=t1;
      }
      for(int i=2;i<=n;i++)
       for(int j=1;j+i-1<=n;j++){
        int ends=j+i-1;
         if(a[ends]-a[j]<=t1)      //判断两个补丁能否补下
            dp[j][ends]=t1;
         else if(a[ends]-a[j]<=t2)
            dp[j][ends]=t2;
        for(int k=j;k<ends;k++){
            dp[j][ends]=min(dp[j][ends],dp[j][k]+dp[k+1][ends]);
        }
       }
       printf("%d\n",dp[1][n]);
    }
}
/*
5 20 2 3
2 5 8 11 15
*/
/*
4 20 12 9
1 2 3 13
*/

【Problem E-Dangerous Dive】

【Description】 The recent earthquake in Nlogonia did not affect too much the buildings in the capital, which was at the epicenter of the quake. But the scientists found that it affected the dike wall, which now has a significant structural failure in its underground part that, if not repaired quickly, can cause the

collapse of the dike, with the consequent flooding the whole capital.

The repair must be done by divers, at a large depth, under extremely difficult and dangerous

conditions. But since the survival of the city is at stake, its residents came out in large numbers to

volunteer for this dangerous mission.

As is traditional in dangerous missions, each diver received at the start of his/her mission a small

card with an identification number. At the end of their mission, the volunteers returned the nameplate,

placing it in a repository.

The dike is safe again, but unfortunately it seems that some volunteers did not return from their

missions. You were hired for the grueling task of, given the plates placed in the repository, determine

which volunteers lost their lives to save the city.

Input

The input is composed of two lines. The first line contains two integers N and R, indicating respectively

the number of volunteers that went to the mission and the number of volunteers that returned from

the mission. Volunteers are identified by numbers from 1 to N. The second line contains R integers,

indicating the volunteers which returned from the mission (at least one volunteer returned).

Output

Your program must produce a single line containing the identifiers of the volunteers who did not

return from their missions, in ascending order of their identifications. Leave a blank space after each

identifier (notice that, therefore, there must be a blank space after the last identifier in the line). If

every volunteer returned, the line must contain a single character ‘*’ (asterisc).

这是个水题了,n个人编号1-n,然后输入<=n个数,判断哪些数没有然后输出,全都有就输出“*”

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=1e4+10;
int vis[N],n,m;
int main()
{
    while(~sc(n)){
        sc(m);
        int x;
        memset(vis,1,sizeof(vis));
        for(int i=1;i<=m;i++){
            sc(x);
            vis[x]=0;
        }
        bool flag=false;
        for(int i=1;i<=n;i++){
            if(vis[i]){
                    flag=true;
                printf("%d ",i);
            }
        }
        if(!flag)
            printf("*");
        printf("\n");
    }
}

【Problem F-Triangles】

【Description】You will be given N points on a circle. You must write a program to determine how many distinct equilateral triangles can be constructed using the given points as vertices.

【Input】

The first line of the input contains an integer N, the number of points given. The second line contains N integers Xi, representing the lengths of the circular arcs between two consecutive points in the circle: for 1 ≤ i ≤ (N − 1), Xi represents the length of the arc between between points i and i + 1; XN represents the length of the arc between points N and 1.

【Output】

Your program must output a single line, containing a single integer, the number of distinct equilateral triangles that can be constructed using the given points as vertices.

在一个圆上标有n个点构成的n个弧的长度,问这n个点能组成多少个正三角形。

很明显这个题需要用到前缀和,题目要求正三角形,所以也就是选出来的三个点之间的弧的长度要相等,所以这里在开一个数组记录前缀和,然后用map储存,在枚举每一个点看看这个点加上圆弧长的1/3,和2/3是否有点,有就ans就加1.

如果圆的周长不能被3整除,那么就肯定一个正三角形都没有。

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=1e5+10;
map<int,int>mp;
int n,a[N];
int main()
{
    while(~sc(n)){
            int x;
    mp.clear();
    memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++){
            sc(x);
            a[i]=a[i-1]+x;
            mp[a[i]]=1;
        }
        if(a[n]%3!=0)
            printf("0\n");
        else{
               int ans=0;
            for(int i=1;i<=n;i++)
                if(mp[a[i]+a[n]/3]&&mp[a[i]+2*(a[n]/3)]){
                    ans++;
            }
            printf("%d\n",ans);
        }
    }
}

Guessing Camels

Description

Jaap, Jan, and Thijs are on a trip to the desert after having attended the ACM ICPC World Finals 2015 in Morocco. The trip included a camel ride, and after returning from the ride, their guide invited them to a big camel race in the evening. The camels they rode will also participate and it is customary to bet on the results of the race. 
One of the most interesting bets involves guessing the complete order in which the camels will finish the race. This bet offers the biggest return on your money, since it is also the one that is the hardest to get right. 
Jaap, Jan, and Thijs have already placed their bets, but the race will not start until an hour from now, so they are getting bored. They started wondering how many pairs of camels they have put in the same order. If camel cc is before camel d on Jaap’s, Jan’s and Thijs’ bet, it means that all three of them put c and d in the same order. Can you help them to calculate the number of pairs of camels for which this happened? 
题意:

有三组数据,每组n个1-n的数,在三组数中都满足一个数在另一个数前面,答案就+1,问最后答案是多少

举个例子:

4

2 3 1 4

2 1 4 3

2 4 3 1

三组数中,2都在1前面,2都在4前面,2都在3前面,所以最后输出3

这个题正解或许是CDQ分治?最近虽然在学CDQ分治,可惜还没学会,还是用树状数组做的。

这个题直接求可能比较麻烦,可以先求出来不满足的,然后用总数一减就是答案,那么不满足的怎么求?

可以先记录第一个数组中的数的编号,即p[a[x]]=i,然后去从后往前看第二个数组,因为不包含位置是等于的情况(即2肯定不在2前面)所以先从后往前求第二个数组中的数在第一个数组中的位置,调用求和的函数,求第一个数组中有多少个数在这个数前面,ans就加多少,因为第二个数组是从后往前扫,这样求出来的就是不满足条件的,然后再把这个数的位置也更新进去。

然后可以用类似的办法求第二个数组和第三个数组,第三个数组和第一个数组,类似于两两求逆序对的情况,最后做差即可。

注意记录的变量要用longlong

#include<bits/stdc++.h>
#define lowbit(x) (x)&(-x)
using namespace std;
const int N=2e5+10;
int n,p[N],a[N],b[N],c[N],sum[N];
long long ans;
int solve(int x)
{
    int ans=0;
    while(x){
        ans+=sum[x];
        x-=lowbit(x);
    }
    return ans;
}
void update(int x)
{
    while(x<=n){
        sum[x]++;
        x+=lowbit(x);
    }
}
int main()
{
    while(~scanf("%d",&n)){
            memset(sum,0,sizeof(sum));
            memset(p,0,sizeof(p));
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            p[a[i]]=i;
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&b[i]);
        for(int i=1;i<=n;i++)
            scanf("%d",&c[i]);
            ans=0;
        for(int i=n;i>=1;i--){
            ans+=solve(p[b[i]]);
            update(p[b[i]]);
        }
        for(int i=1;i<=n;i++){
            p[b[i]]=i;
            sum[i]=0;
        }
        for(int i=n;i>=1;i--){
            ans+=solve(p[c[i]]);
            update(p[c[i]]);
        }
        for(int i=1;i<=n;i++){
            p[c[i]]=i;
            sum[i]=0;
        }
        for(int i=n;i>=1;i--){
            ans+=solve(p[a[i]]);
            update(p[a[i]]);
        }
        printf("%lld\n",(1LL*n*(n-1)-ans)>>1);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值