20170925“切题如切菜杯”水题模拟赛 第二弹

T1:短

 给出一张有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

solution: 裸的不能再裸的最短路,但用spfa会被卡,就上dij代码

#include<cstdio>  
#include<algorithm>  
#include<queue>  
#include<vector>  
using namespace std;  
const int maxn = 5000+100;  
const int inf = 0x7fffffff;  
typedef pair<int,int> P;  
struct edge{  
    int to,cost;  
};  
vector<edge> G[maxn];  
int n,m,ans;  
int dis1[maxn],disn[maxn];  
void Dijkstra(int src,int dis[]) 
{  
    priority_queue< P,vector<P>,greater<P> >que;  
    dis[src]=0;  
    que.push(P(dis[src],src));  
    while(!que.empty()){  
        P p=que.top();  
        que.pop();  
        int u=p.second,d=p.first;  
        if(d>dis[u]) continue;  
        for(int i=0;i<G[u].size();i++){  
            edge e=G[u][i];  
            if(e.cost+d<dis[e.to]){  
                dis[e.to]=d+e.cost;  
                que.push(P(dis[e.to],e.to));  
            }  
        }  
    }  
}  
void solve()  
{  
    fill(dis1+1,dis1+1+n,inf);  
    fill(disn+1,disn+1+n,inf);  
    Dijkstra(1,dis1);  
    Dijkstra(n,disn);  
    ans=0x7fffffff;  
    for(int i=1;i<=n;i++)   
    for(int j=0;j<G[i].size();j++){  
        int v=G[i][j].to,d=G[i][j].cost;  
        if(dis1[i]+d+disn[v]>dis1[n]){  
            ans=min( ans , dis1[i]+ d + disn[v] );  
        }  
    }  
}  
int main()  
{  
    freopen("short.in","r",stdin);
    freopen("short.out","w",stdout); 
    scanf("%d%d",&n,&m);  
    int u,v,w;  
    edge e;  
    for(int i=1;i<=m;i++){  
        scanf("%d%d%d",&u,&v,&w);  
        e.to=v,e.cost=w;  
        G[u].push_back(e);  
        e.to=u;  
        G[v].push_back(e);  
    }  
    solve();  
    printf("%d\n",ans);  
    return 0;  
}  

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

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

输入格式:

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

输出格式:

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

样例输入

样例输出

6

6

 

样例解释:

11221212,1221,2112,2121,2211。

数据范围:

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

solution:

dp[i][j]表示长度为i时分成j段的方案数,随便转移。

这是正解,当然因为本题比较特殊,附上两个暴力代码。

正常暴力

#include<cstdio>
using namespace std;
int main()
{
    freopen("quad.in","r",stdin);
    freopen("quad.out","w",stdout);
    long long t,n,sum=0;
    scanf("%lld",&n);
    for(long long i=1;i<=n-3;i++)
    for(long long j=1;j<n-i;j++)
    for(long long k=1;k<n-i-j;k++)
    {
        long long m=n-i-j-k;
        if((i+j+k>m)&&(i+k+m>j)&&(i+m+j>k)&&(k+m+j>i))
        sum++;
    }    
    printf("%lld\n",sum);
}

优化暴力(from巨神lzb

#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);
} 
} 

正解

#include <cstdio>
#include <cstring>
 
int n,mid;
int dp[2501][5];

int getint()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-f;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
 
int min(int a,int b)
{
    return a<b?a:b;
}
 
int main()
{
    freopen("quad.in","r",stdin);
    freopen("quad.out","w",stdout);
    n=getint();
    mid=(n-1)>>1;
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=4;j++)
        {
            for(int k=1;k<=min(mid,i);k++) dp[i][j]+=dp[i-k][j-1];
        }
    }
    printf("%d",dp[n][4]);
    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。

solution:dp[i][j]表示前i天做了j题后该天可能剩下的最多的钱的数量。那么dp[i][j]可以转移到dp[i][j+1]dp[i][j+2]……只要满足剩下的钱不少于0并且下个月的钱够还即可。同时可以算出dp[i+1][j+1]dp[i+1][j+2]……最后输出满足dp[i][m]存在值的最小i。

#include <cstdio>
#include <cstring>
#define INF 0x3f3f3f3f
int n,m,t1,t2;
int a[301],b[301];
int dp[501][301];
int getint()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-f;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
 
int max(int a,int b)
{
    return a>b?a:b;
}
 
int main()
{
    freopen("solve.in","r",stdin);
    freopen("solve.out","w",stdout);
    n=getint(),m=getint();
    for(int i=1;i<=m;i++) a[i]=getint(),b[i]=getint();
    memset(dp,INF,sizeof(dp));
    dp[2][0]=n;
    int i=2;
    while(dp[i][m]==INF)
    {
        for(int j=m;j>=0;j--)
        {
            if(dp[i][j]!=INF)
            {
                int k=j+1;
                t1=dp[i][j],t2=dp[i+1][j]=n;
                while(t1>=a[k]&&t2>=b[k])
                {
                    t1-=a[k];
                    t2-=b[k];
                    dp[i][k]=(dp[i][k]==INF?t1:max(dp[i][k],t1));
                    dp[i+1][k]=(dp[i+1][k]==INF?t2:max(dp[i+1][k],t2));
                    k++;
                }
            }
        }
        i++;
    }
    printf("%d",i);
    return 0;
}

T4:个人卫生综合征

每天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

 

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define INF 0x3f3f3f3f
 
struct path
{
    int to,v;
};
struct node
{
    int num,v;
    bool operator <(const node &b) const
    {
       return v>b.v;
    }
};
std::vector<path> g[10001];
std::priority_queue<node> q;
int m,n,k,ans;
int dist[10001][21];
bool vis[10001][21];

int getint()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-f;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
 
int min(int a,int b)
{
    return a<b?a:b;
}
 
void dij()
{
    node now;
    memset(dist,INF,sizeof(dist));
    memset(vis,false,sizeof(vis));
    dist[1][0]=0;
    q.push((node){1,0});
    while(!q.empty())
    {
        now=q.top();
        q.pop();
        int t1=now.num%(n+1),t2=now.num/(n+1);
        vis[t1][t2]=true;
        for(int i=0;i<int(g[t1].size());i++)
        {
            path t=g[t1][i];
            if((!vis[t.to][t2])&&dist[t.to][t2]>dist[t1][t2]+t.v)
            {
                dist[t.to][t2]=dist[t1][t2]+t.v;
                q.push((node){t2*(n+1)+t.to,dist[t.to][t2]});
            }
            if((!vis[t.to][t2+1])&&t2<k&&dist[t.to][t2+1]>dist[t1][t2])
            {
                dist[t.to][t2+1]=dist[t1][t2];
                q.push((node){(t2+1)*(n+1)+t.to,dist[t.to][t2+1]});
            }
        }
    }
}
 
int main()
{
    freopen("school.in","r",stdin);
    freopen("school.out","w",stdout);
    n=getint(),m=getint(),k=getint();
    for(int i=1;i<=m;i++)
    {
        int a=getint(),b=getint(),v=getint();
        g[a].push_back((path){b,v});
        g[b].push_back((path){a,v});
    }
    dij();
    ans=INF;
    for(int i=0;i<=k;i++) ans=min(ans,dist[n][i]);
    printf("%d",ans);
    return 0;
}

 

posted @ 2017-09-26 17:22  思故忆今  阅读(132)  评论(0编辑  收藏  举报