校内模拟赛(20170924)

四校很丧,但是学长的题目更简单

lrb学长的题目为什么都要倒着切,不懂QAQ

————————————————我是分割线————————————————

T1:个人卫生综合征

每天BBS都要从家里经过城市中的一段路到学校刷五三。城市中一共有n个路口和m条双向道路,每条双向道路都连接着两个路口aibi且有一定的时间花费viBBS家编号为1,学校编号为n。今天,BBS由于个人卫生综合征导致他很迟才离开家,他想用膜法改变k条道路的长度使通过其的时间花费vi变为0。现在他问你改变道路长度之后他到学校的最小时间花费是多少?

 

输入格式:

第一行为三个整数n、m、k,接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个路口和通过其所用的时间。

输出格式:

一个整数,表示BBS到学校的最小时间花费。

 

样例输入

样例输出

4 4 1
1 2 10
2 4 10
1 3 1
3 4 100

1

 

样例解释:

更新3->4的道路,最短路线为1->3->4,用时为1+0=1。

数据范围:

对于100%的数据:1<=n<=10000,1<=m<=50000,1<=k<=201<=vi<=1000000

————————————————我是分割线————————————————

emmm本次考试最丧的一题(但不是最坑的QAQ),但是其实也很好想,我们把整张图复制k份,然后跑dij就好了QAQ

#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
#define MN 100005
using namespace std;
int head[MN],dis[MN][25],num,n,m,k,x,y,v;
bool vis[MN][25];
struct node{
    int num,d;
    friend bool operator<(node a,node b){return a.d>b.d;}
};
struct edge{
    int to,next,w;
}g[MN];
void ins(int u,int v,int w){g[++num].next=head[u];head[u]=num;g[num].to=v;g[num].w=w;}
priority_queue<node> q;
void dij(){
    node now;
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));dis[1][0]=0;
    q.push((node){1,0});
    while(!q.empty()){
        now=q.top();q.pop();//printf("%d\n",now);
        int t1=(now.num%n==0?n:now.num%n),t2=now.num/n;vis[t1][t2]=true;
        for(int i=head[t1];i;i=g[i].next){
            if((!vis[g[i].to][t2])&&(dis[g[i].to][t2]>dis[t1][t2]+g[i].w)){
                dis[g[i].to][t2]=dis[t1][t2]+g[i].w;
                q.push((node){t2*n+g[i].to,dis[g[i].to][t2]});
            }
            if((!vis[g[i].to][t2+1])&&t2<k&&dis[g[i].to][t2+1]>dis[t1][t2]){
                dis[g[i].to][t2+1]=dis[t1][t2];
                q.push((node){(t2+1)*n+g[i].to,dis[g[i].to][t2+1]});
            }
        }
    }
}
int main(){
    freopen("school.in","r",stdin);
    freopen("school.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&v),ins(x,y,v),ins(y,x,v);
    dij();
    int ans=inf;
    for(int i=0;i<=k;i++)ans=min(ans,dis[n][i]);
    printf("%d\n",ans);
    fclose(stdin);
    fclose(stdout);
}

————————————————我是分割线————————————————

T2:你的四边形已如风中残烛

  LGL有一根长为n的木板。现在他想要把它砍成四段长度为整数的木板来做一个四边形,请问他有多少种不同的砍法?注意:四段长度为1、1、2、1和四段长度为1、2、1、1算两种砍法。

 

输入格式:

第一行为一个整数 n,表示木板的长度。

输出格式:

一个整数,不同的砍法数量。

 

样例输入

样例输出

6

6

 

样例解释:

11221212,1221,2112,2121,2211。

数据范围:

对于100%的数据:1<=n<=2500

————————————————我是分割线————————————————

当然,我们可以写正解,不过你可以用一些奇特的技巧通过此题,比如:打表。。。。

下面贴上打表程序!

#include<cstdio>
using namespace std;
int main(){
    freopen("bll.out","w",stdout);
    for(int n=0;n<=2500;n++){
        long long ans=0;
        for(int i=1;i<=n/4;i++)
            for(int j=i;j<=(n-i)/3;j++)
                for(int k=j;k<=(n-i-j)/2;k++)if(n-i-j-k<i+j+k){
                    if(i==j&&j==k&&k==n-i-j-k)ans++;
                    else if((i==j&&j==k)||(j==k&&k==n-i-j-k))ans+=4;
                    else if(i==j&&k==n-i-j-k)ans+=6;
                    else if(i==j||k==n-i-j-k||j==k)ans+=12;
                    else ans+=24;
                }
        printf("%lld,",ans);
    }
}

242.9秒出正解,贼快QAQ

好吧,正解我也说一下,就是枚举最小的和第二小的,然后通过数学方法O(1)统计剩下的两条边的情况。

#include<cstdio>
int n,mid,ans=0;
int main(){
    freopen("quad.in","r",stdin);
    freopen("quad.out","w",stdout);
    scanf("%d",&n); mid=(n+1)/2-1;
    for(int i=1;i<=mid;++i){
        for(int j=1;j<=mid;++j){
            int sum=n-i-j;
            ans+=sum>mid?mid+mid-sum+1:sum-1;
        }
    }
    printf("%d",ans);
    return 0;
}

————————————————我是分割线————————————————

T3:生命不息刷题不止

 YYH有n道题要做。但是由于他上课做某些事,导致他一题都不会做,只好请LGL代打。LGL为了买自己心爱的坦克,他做第i题要收两笔钱:一笔在YYH叫他做题当天收,另外一笔在叫他做题的第二天收。YYH每天结束的时候都会把剩下的所有钱花光,然后再从父亲LRB处得到m元零花钱用来请LGL做题(也就是说,第一天的时候YYH是没有钱请LGL做题的,每一天用来请LGL做题所用的钱都是前一天LRB给的)。而且,YYH做的题目难度是循序渐进的:就算强如LGL,在做第i题之前也要先把第1到i-1题全部做完。请问YYH将所有题目做完并且把所有钱都付给LGL的最小天数。

 

输入格式:

第一行为两个整数m、n,接下来的n行每一行都有两个数aibi,分别表示LGL做第i题所收的两笔钱。

输出格式:

一个整数,表示最小天数。

 

样例输入

样例输出

100 5
40 20
60 20
30 50
30 50
40 40

6

 

样例解释:

第二天做1、2两题,第三天做3、4两题,第五天做5。在第六天的时候所有钱都付完。

 

数据范围:

对于100%的数据:1<=n<=300,1<=aibi<=m<=1000。

————————————————我是分割线————————————————

神奇的题目!最坑了!

看上去怎么都可以贪心。。但是其实不行的QAQ

比如说:

————————————————我是分割线————————————————

T4:短

  给出一张有n个点和m条双向边的图,要求求出1到n的次短路的长度。一条边可以多次通过。

 

输入格式:

第一行为两个整数n和m。接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个点和他的长度。

 

输出格式:

一个整数,表示次短路的长度。

 

样例输入

样例输出

4 4
1 2 100
2 4 200
2 3 250
3 4 100

450

 

样例解释:

最短:1->2->4。

次短:1->2->3->4。

 

数据范围:

对于 100%的数据:1<=n、vi<=50001<=m<=100000

————————————————我是分割线————————————————

暴力dij,不解释,本场最水的题目

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define MN 200005
#define M 5005
using namespace std;
int head[M],d1[M],d2[M],n,m,num;
struct e{
    int to,next,w;
}g[MN];
void ins(int u,int v,int val){g[++num].next=head[u];head[u]=num;g[num].to=v;g[num].w=val;}
void insw(int u,int v,int w){ins(u,v,w);ins(v,u,w);}
void swap(int &a,int &b){a^=b;b^=a;a^=b;}
struct edge{
    int to,value;
    edge(int to,int value):to(to),value(value) {}
    friend bool operator <(edge a,edge b){
        return a.value>b.value;
    }
};
priority_queue<edge>q;
void dij(){
    d1[1]=0;q.push(edge(1,0));
    while(!q.empty()){
        edge tmp=q.top();q.pop();if(tmp.value>d2[tmp.to])continue;
        for(int i=head[tmp.to];i;i=g[i].next){
            int dd=tmp.value+g[i].w;
            if(dd==d1[g[i].to])continue;
            if(dd<d1[g[i].to]){
                swap(dd,d1[g[i].to]);
                q.push(edge(g[i].to,d1[g[i].to]));
            }
            if(dd<d2[g[i].to]){
                swap(dd,d2[g[i].to]);
                q.push(edge(g[i].to,d2[g[i].to]));
            }
        }
    }
}
int main(){
    freopen("short.in","r",stdin);
    freopen("short.out","w",stdout);
    scanf("%d%d",&n,&m);memset(d1,0x3f,sizeof(d1));memset(d2,0x3f,sizeof(d2));
    int x,y,val;
    for(int i=1;i<=m;i++)scanf("%d%d%d",&x,&y,&val),insw(x,y,val);
    dij(),printf("%d\n",d2[n]);
    return 0;
    fclose(stdin);
    fclose(stdout);
}

 

posted @ 2017-09-26 17:59  ghostfly233  阅读(155)  评论(0编辑  收藏  举报