2017年10月17日-Test

来源:互联网 发布:java 反射写法 编辑:程序博客网 时间:2024/05/01 22:27

今天这次考试,其实并不是很难,就是这些较为基础的东西被忽略了过去,十分的懊悔。今天在这总结分析一下,先贴一下成绩这里写图片描述

题目大意

problem-1,给出一个长度为n的序列,求最少交换次数使得这个序列成为不下降序列

problem-2, 学校有s节课,从ti开始上课,上课的时间为si,如果上了第i节课,你的做题能力将变成ci。有N类作业,每类作业数量不限,每类作业完成一份所需要的时间为ai,做某类作业需要的做题能力达到qi才能完成。在每个时刻你可以选择上课、休息、做作业,如果选择上课则必须上完整节课,如果选择做作业必须花完整的ai时间做,同一时刻只能上一节课或做一份作业。因为各种原因,在T时刻后必须停止学习。求在时限内最多可以完成几份作业。开始时,你的做题能力为1,时刻为1。

problem-3,有一个奇怪的地方,开车过路要收过路废,经过城市还要收过城费(走一次只收一次过城费,那就是经过城市所有过城费最高的一个),现给出每个城市的过城费和所有过路费共询问Q次,求A到B的最少费用

为了更清楚,我贴一下输入格式

这里写图片描述
sulution-1,逆序对问题,其实也没什么好讲的,就是个模板题,只是考前不会

/**************************    Name:sopgist    How to get:FZ    By:Shine_Sky**************************/#include<iostream>#include<cstdio>#define f(i,a,b)    for(register int i = a;i <= b; ++ i)#define fd(i,a,b)   for(register int i = a;i >= b; -- i)using namespace std;inline long long read(){    long long data  =  0 , w  =  1; char ch = 0;    while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();    if(ch == '-') w = -1,ch = getchar();    while(ch >= '0' && ch <= '9') data = data * 10 + ch - '0',ch = getchar();    return data*w;}inline void write(long long x){    if(x < 0) putchar('-') , x = -x;    if(x / 10) write(x / 10);    putchar(x % 10 + '0');}const long int N = 5 * 1e5 + 7;long long a[N] , b[N];int n = read();long long ans;inline void Find(long long l , long long r){    if(l >= r)  return;    long long Mid = (l + r) >> 1;    Find(l , Mid);    Find(Mid + 1, r);    long long i = l , j = Mid + 1 , now = l;    while(i <= Mid && j <= r)    {        if(a[i] > a[j])        {            b[now ++] = a[j ++];            ans += Mid - i +1;//核心        }        else            b[now ++] = a[i ++];    }    while(i <= Mid) b[now ++] = a[i ++];    while(j <= r)   b[now ++] = a[j ++];    f(i,l,r)        a[i] = b[i];}int main(){    f(i,1,n)        a[i] = read();    Find(1,n);    write(ans);    return 0;}

solution-2这道题贪心+DP,然而没想出这种那个方法,一开始用DFS做的全部都是T,T,T

/**************************    Name:class    How to get:FZ    By:Shine_Sky**************************/#include<iostream>#include<cstdio>#include<algorithm>#define f(i,a,b)    for(register int i = a;i <= b; ++ i)#define fd(i,a,b)   for(register int i = a;i >= b; -- i)using namespace std;inline int read(){    int data  =  0 , w  =  1; char ch = 0;    while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();    if(ch == '-') w = -1,ch = getchar();    while(ch >= '0' && ch <= '9') data = data * 10 + ch - '0',ch = getchar();    return data*w;}inline void write(int x){    if(x < 0) putchar('-') , x = -x;    if(x / 10) write(x / 10);    putchar(x % 10 + '0');}const int M = 10000 + 7;int T , m , n , can[M/10] , f[M];struct lessons{    int t,s,c;}a[M];inline bool cmp(lessons a , lessons b){    return a.t < b.t;}int main(){    //freopen("class.in" , "r" ,stdin);    //freopen("class.out" , "w" ,stdout);    T = read() , m = read() , n = read();    f(i,1,m)        a[i].t = read() , a[i].s = read() , a[i].c = read();    sort(a + 1 , a + 1 + m , cmp);    f(i,0,100)  can[i] = 123456789;    f(i,1,n)    {        int A = read() , P = read();        f(j,P,100)            if(can[j] < A)  break;            else    can[j] = A;    }//can[i]表示能力值为i时最少花多少时间做一份作业    a[0].t = a[0].c = 1;//一开始能力值和时刻都是1    a[++ m].t = T + 1;//这题目可能有点题意不清,到底是上到T时刻还是T+1时间段    //要是上到T时刻就过不去样例    //f[i]表示考虑到第i节课,最大的写完作业数    f(i,1,m)        f(j,0,i-1)            if(a[i].t - (a[j].t + a[j].s) >= 0)//这两节课是否有空闲时间                f[i] = max(f[i] , f[j] + (a[i].t - (a[j].t + a[j].s))/can[a[j].c]);    //因为上完第j节课能力值就变为a[j].c所以呢,我们用第j节课到i节课的下课时间写作业    //也就是说上面的状态转移方程如果取后面的那就说明上第j节课    write(f[m]);    return 0;}

solution-3这道题在考场上时,看到还有点权这东西是完全懵逼的,感觉见都没见过,但是用的也是正解弗洛里得,然而最大点权处理错误,看过std后,里面有一个精髓就是把点权从小到大排序,经过几次画图研究发现这样的确对处理最大点权很有作用,证明就在下面的注释了。

/**************************    Name:cost    How to get:FZ    By:Shine_Sky**************************/#include<iostream>#include<cstdio>#include<algorithm>#define f(i,a,b)    for(register int i = a;i <= b; ++ i)#define fd(i,a,b)   for(register int i = a;i >= b; -- i)using namespace std;inline int read(){    int data  =  0 , w  =  1; char ch = 0;    while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();    if(ch == '-') w = -1,ch = getchar();    while(ch >= '0' && ch <= '9') data = data * 10 + ch - '0',ch = getchar();    return data*w;}inline void write(long long x){    if(x < 0) putchar('-') , x = -x;    if(x / 10) write(x / 10);    putchar(x % 10 + '0');}const int  N = 300 +7; int n , m;long long Map[N][N] , ans[N][N];struct Node{    int c , i;}node[N];//之后要排序(但是路是不知道的,所以要记录一下,调整路)inline bool cmp(Node a , Node b){    return a.c < b.c;}int main(){    n = read() , m = read();    f(i,1,n)        node[i].c = read() , node[i].i = i;    sort(node + 1 , node + 1 + n , cmp);    /***************************************        为什么要从小到大排序呢,因为我们之后就要用        弗洛里得算法求最短路,我们会枚举中间点        当中间点编号为1时,最大点肯定大于等于它的        过城费(因为他最小),也就是说最大过城废就在        i,j,k三点之间,要是K>=1那么i->k的路要么被之前的小K推过        那么最大点就是i或者k,要么他们两个可以直接到达        最大点也是i或者k,同理k->j也是一样的        最后我们在i.c,j.c,k.c中取最大更新答案就是了    ****************************************/    f(i,1,n)        f(j,1,n)            Map[i][j] = ans[i][j] = 1 << 30;    f(i,1,m)    {        int u = read() , v = read();        long long w;    scanf("%lld" , &w);        Map[u][v] = Map[v][u] = min(w , Map[v][u]);    }    f(k,1,n)        f(i,1,n)            f(j,1,n)            {                int a = node[k].i , b = node[i].i , c = node[j].i;                Map[c][b] = Map[b][c] = min(Map[b][c] , Map[b][a] + Map[a][c]);                int Max = max(node[k].c , max(node[i].c , node[j].c));                ans[c][b] = ans[b][c] = min(ans[b][c] , Max + Map[b][c]);            }    int t = read();    while(t--)    {        int A = read() , B = read();        write(ans[A][B]);        puts("");    }    return 0;}