欢迎来到Soray88的博客

本人蒟蒻一枚。

泉五培训Day3

T1 家庭作业

题目

【问题描述】

小P为了能高效完成作业,规定每项作业花一个单位时间。

他的学习日从0时刻开始,有100000个单位时间。在任一时刻,他都可以选择编号1~N的N项作业中的任意一项作业来完成。

因为他在每个单位时间里只能做一个作业,而每项作业又有一个截止日期,所以他很难有时间完成所有N个作业,虽然还是有可能。

对于第i个作业,有一个截止时间D_i,如果他可以完成这个作业,那么他可以获得分数P_i.

 在给定的作业分数和截止时间下,小P能够获得的分数最大为多少呢?答案可能会超过32位整型。

【输入格式】(homework.in)

第1行:一个整数N.

第2~N+1行:第i+1行有两个用空格分开的整数:D_i和P_i.

【输出格式】(homework.out)

输出一行,里面有一个整数,表示最大获分值。

【样例输入】

3

2 10

1 5

1 7

【样例输出】

17

【样例解释】

第1个单位时间完成第3个作业(1,7),然后在第2个单位时间完成第1个作业(2,10)以达到最大分数

【数据范围】

对于前20%的数据,1 <= N <= 100.

对于前40%的数据,1 <= N <= 1000.

对于前60%的数据,1 <= N <= 20000.

对于100%的数据,1 <= N <= 100000,

1 <= D_i <= 100000,1 <= P_i <= 1000000000

解析

很明显这是一道贪心题。

只需按分数从小到大排序,再放到离结束时间最近且未被占用的时间,之后稍微优化一下便行了。

Code

#include <algorithm> 
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
const int N=100001;
int n;
long long ans;
int f[N];
struct rec{
    int d,p;
}work[N];
bool cmp(rec a,rec b)
{
    return a.p>b.p;
}
int find(int x)
{
    if(f[x]<0) return x;
    return f[x]=find(f[x]);
}
int main()
{
    memset(f,-1,sizeof(f));
    cin>>n;
    for(int i=1;i<=n;i++) cin>>work[i].d>>work[i].p;
    sort(work+1,work+1+n,cmp);
    for(int i=1;i<=n;i++)
    {
        int r=find(work[i].d);
        if(r>0) ans+=1LL*work[i].p,f[r]=r-1;
    }
    cout<<ans;
    return 0;
}
View Code

 

 

 

 

 

 

T2 方程式

题目

【题目描述】

求解方程a0+a1x+a2x2+···+anxn=0。

注意:①数据保证所有根均为小于等于20的正整数。

         ②数据保证方程最高次项的系数为1。

         ③重根也要输出。

如方程1-2x+x2=0应该输出1 1。

如方程-2+5x-4x2+x3=0应该输出1 1 2。

【输入格式】

 第一行一个数表示这是一个n次方程。

 第二行共n+1个数,第i个数ai表示xi-1前的系数。

【输出格式】

 一共n个数,从小到大依次输出方程的n个解。

【输入样例1

2

1 -2 1

【输出样例1

1 1

【输入样例2

3

-2 5 -4 1

【输出样例2

1 1 2

【数据规模】

 对于30%的数据,n=2。

 对于另外20%的数据,保证方程没有重根。

 对于100%的数据,n<=7,ai<=109

解析

如果没有重根的情况,直接模拟即可。

而有重根的情况,模拟多项式除法即可。

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
long long a[20],b[20],n;
long long cf(int a,int m) //乘方 
{
    long long sum=1;
    for(int i=1;i<=m;i++) sum*=a;
    return sum;
}
long long cal(int i)
{
    int sum=0;
    for(int j=0;j<=n;j++) sum+=a[j]*cf(i,j);
    return sum;
}
int main()
{
    cin>>n;
    for(int i=0;i<=n;i++) cin>>a[i];
    for(int i=1;i<=20;i++)
    {
        while(cal(i)==0)
        {
            memset(b,0,sizeof(b));
            cout<<i<<" ";
            for(int j=n;j>=0;j--)
                if(a[j]!=0&&a[j+1]!=0)
                {
                    b[j]=a[j+1];
                    a[j]+=a[j+1]*i;
                }
            for(int j=n;j>=0;j--) a[j]=b[j];
        }
    }
    return 0;
}
View Code

 

 

 

 

 

 

T3 做梦

题目

【问题描述】

Lqa的家是n层的大楼。

Lqa的电梯可以采用以下四种方式移动:

  1. 回到第一层。
  2. 向上移动a层;
  3. 向上移动b层;
  4. 向上移动c层;

现在hjy来到了Lqa的家,现在他在Lqa家的第一层,碰巧电梯也在第一层。Hjy想知道,他可以乘坐电梯前往的楼层数。

【输入格式】

第一行一个整数n,表示摩天大楼的层数。

第二行三个正整数,分别表示题目中的a,b,c。

【输出格式】

一行一个整数,表示hjy可以到达的楼层数。

【样例输入】

15

4 7 9

【样例输出】

9

【样例解释】

可以到达的楼层有:1,5,8,9,10,12,13,14,15

【数据范围】

对于20%的数据,1≤h, x, y, z≤100;

对于40%的数据,1≤h, x, y, z≤105

对于100%的数据,1≤h≤1018,1≤x, y, z≤105

解析

原题啊——跳楼机

令f(i)表示仅通过操作2和操作3能达到的 mod x=i的最小楼层。

于是得出状态转移方程

f(i+y)=f(i)+y;

f(i+z)=f(i)+z。

能达到 mod x=i+y的最小楼层,即在能达到 mod x=i的最小楼层上再执行一遍操作2。

再来看一遍最短路的求法。

f(y)=f(x)+edge(i)。(y为子节点,x为父节点,edge为权值)

对比一下上面的状态转移方程,是不是很像?

于是让(i+y)与(i+z)成为点,让y,z成为权值,即可求出f(i)。

ans+=(h-f[i])/x+1;

由于f(i)是在不使用操作1的情况下,所以h和f(i)之间的差值由操作1来完成。

而每用一次操作1,就可以到达一个新楼层,所以答案就要累加上进行操作1的次数。

即(h-f[i])/x+1(因为除法是向下取整,所以答案得+1)。

Code

#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
using namespace std;
const int N=1e5+3;
const int INF=0x3f3f3f3f;
long long h,x,y,z;
long long f[N],ans;
bool vis[N];
int tot,ver[N*2],Next[N*2],edge[N*2],head[N];
void add(int x,int y,int z)
{
    ver[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
    edge[tot]=z;
}
void spfa()
{
    memset(f,INF,sizeof(f));
    memset(vis,0,sizeof(vis));
    queue<int> qwq;
    qwq.push(1);
    vis[1]=1;
    f[1]=1;
    while(!qwq.empty())
    {
        int x=qwq.front();qwq.pop();
        vis[x]=0;
        for(int i=head[x];i;i=Next[i])
        {
            int y=ver[i];
            if(f[y]>f[x]+edge[i])
            {
                f[y]=f[x]+edge[i];
                if(!vis[y])
                {
                    qwq.push(y);
                    vis[y]=1;
                 } 
            }
        }
    }
}

int main()
{
    cin>>h>>x>>y>>z;
    if(x==1 || y==1 || z==1){cout<<h;return 0;} //特判 
    for(int i=0;i<x;i++)
    {
        //关键点 
        add(i,(i+y)%x,y);
        add(i,(i+z)%x,z);
    }
    spfa();
    for(int i=0;i<x;i++)
        if(f[i]<=h) ans+=(h-f[i])/x+1;    //记得+1 
    cout<<ans;
    return 0;
}
View Code

 

posted @ 2019-01-30 14:58  Soray88  阅读(217)  评论(0编辑  收藏  举报