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<=5000,1<=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

样例解释:

1122,1212,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行每一行都有两个数ai和bi,分别表示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<=ai、bi<=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条双向道路,每条双向道路都连接着两个路口ai、bi且有一定的时间花费vi。BBS家编号为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<=20,1<=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;
}
时间: 2024-08-29 20:13:05

20170925“切题如切菜杯”水题模拟赛 第二弹的相关文章

2017.9.10所谓“切题如切菜杯”水题模拟赛(;&#180;д`)ゞ

T1:MHM LGL今天一共要上n节课,这n节课由0标号至n.由于过度劳累,除了第0节课和第n节课,LGL还打算睡上m节课,所以他做了一个睡觉计划表.通过小道消息,LGL得知WQ今天会在学校中检查,所以他想少睡k节课.但是由于某些原因,他又想使相邻的两节睡觉的课之间上的课数量的最小值最大.由于他很困,所以他请你来帮他计算这个值.   输入格式: 第一行为三个整数 n.m.k,接下来的m行为m个整数ai,表示睡觉计划表中LGL想要睡觉的课. 输出格式: 一个整数,表示题目所求的值. 样例输入 样例

CSP-S全国模拟赛第二场 【nan】

A.count 本场比赛最难的题... 隔板法组合数容斥 xjb 搞搞就好了 //by Judge #include<cstdio> #include<iostream> #define Rg register #define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i) #define fd(i,a,b) for(Rg int i=(a),I=(b)-1;i>I;--i) #define ll long long using

CodeForces 686A Free Ice Cream (水题模拟)

题意:给定初始数量的冰激凌,然后n个操作,如果是“+”,那么数量就会增加,如果是“-”,如果现有的数量大于等于要减的数量,那么就减掉,如果小于, 那么孩子就会离家.问你最后剩下多少冰激凌,和出走的孩子数量. 析:多水的一个题,就是一个模拟,如果是+,就加上,如果是‘-’,就判断一下,如果不够,就记录下来. 代码如下: #include <iostream> #include <cmath> #include <cstdlib> #include <set>

ACM: NBUT 1105 多连块拼图 - 水题 - 模拟

NBUT 1105  多连块拼图 Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format: Practice Appoint description:  System Crawler  (Aug 12, 2016 9:32:14 AM) Description 多连块是指由多个等大正方形边与边连接而成的平面连通图形. -- 维基百科 给一个大多连块和小多连块,你的任务是判断大多连块是否可以由两个这样的小多连块拼成.小多连块只能

CodeForces 342B Xenia and Spies (水题模拟,贪心)

题意:给定 n 个间谍,m个区间,一个 s,一个f,然后从 s开始传纸条,然后传到 f,然后在每个 t 时间在区间内的不能传,问你最少的时间传过去. 析:这个题,就模拟一下就好,贪心策略,能传就传,找好方向,一直传就行,传到 f 就结束. 代码如下: #include <bits/stdc++.h> using namespace std; struct node{ int l, r, t; bool operator < (const node &p) const{ retur

CodeForces 731B Coupons and Discounts (水题模拟)

题意:有n个队参加CCPC,然后有两种优惠方式,一种是一天买再次,一种是买两天,现在让你判断能不能找到一种方式,使得优惠不剩余. 析:直接模拟,如果本次是奇数,那么就得用第二种,作一个标记,再去计算下一个. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #inclu

CodeForces 723B Text Document Analysis (水题模拟)

题意:给定一行字符串,让你统计在括号外最长的单词和在括号内的单词数. 析:直接模拟,注意一下在左右括号的时候有没有单词.碰到下划线或者括号表示单词结束了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include

CodeForces 339B Xenia and Ringroad(水题模拟)

题意:给定 n 个地方,然后再给 m 个任务,每个任务必须在规定的地方完成,并且必须按顺序完成,问你最少时间. 析:没什么可说的,就是模拟,记录当前的位置,然后去找和下一个位置相差多长时间,然后更新当前位置即可. 代码如下: #include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; typedef long long LL; int main(){ int n, m, x; while(cin >>

codeforces水题100道 第二十五题 Codeforces Round #197 A. Helpful Maths (Div. 2) (strings)

题目链接:http://www.codeforces.com/problemset/problem/339/A题意:重新组合加法字符串,使得按照1,2,3的顺序进行排列.C++代码: #include <iostream> #include <string> using namespace std; int cnt[3]; string s, ans = ""; int main() { cin >> s; int len = s.length();