1. 程式人生 > >20170924校內訓練

20170924校內訓練

type int clu con first names hid out top

個人衛生綜合征

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

樣例解釋:

更新3->4的道路,最短路線為1->3->4,用時為1+0=1。

數據範圍:

對於100%的數據:1<=n<=10000,1<=m<=50000,1<=k<=20,1<=vi<=1000000。

dijsktra。用d[i][j]表示i點與1號點用了j次魔法的距離

更新時,d[i.to][j]=d[i][j]+cost[i][j](不用魔法),d[i.to][j+1]=d[i][j](j+1<k)(用魔法)

入堆時,再記下當前用了多少次魔法。即pair<int,pair<int,int> > 第一個int記距離,第二的int記使用魔法次數,第三個int記標號

岀堆的條件改為距離>dist[標號][使用魔法次數]

技術分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int> p;
typedef pair<int,p>P;
priority_queue<P,vector<P>,greater<P> >q;
int n,m,k;
int dist[10010][25];
int h[10010
],to[100010],next[100010],cost[100010],tot=0; void ins(int u,int v,int w){next[++tot]=h[u];h[u]=tot;to[tot]=v;cost[tot]=w;} void dij(int S) { memset(dist,127,sizeof(dist)); for(int i=0;i<=k;i++)dist[S][i]=0,q.push(P(0,p(i,S))); while(!q.empty()) { P pp=q.top();q.pop();int K=pp.second.first,u=pp.second.second,d=pp.first; if(d>dist[u][K])continue; for(int i=h[u];i;i=next[i]) { int v=to[i]; if(dist[v][K]>d+cost[i]){dist[v][K]=d+cost[i];q.push(P(dist[v][K],p(K,v)));} if(K+1<=k&&dist[v][K+1]>d){dist[v][K+1]=d;q.push(P(dist[v][K+1],p(K+1,v)));} } } } 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++) { int x,y,z;scanf("%d%d%d",&x,&y,&z);ins(x,y,z);ins(y,x,z); } dij(1);printf("%d",dist[n][k]); return 0; }
View Code

你的四邊形已如風中殘燭

LGL有一根長為n的木板。現在他想要把它砍成四段長度為整數的木板來做一個四邊形,請問他有多少種不同的砍法?註意:四段長度為1、1、2、1和四段長度為1、2、1、1算兩種砍法。

輸入格式:

第一行為一個整數 n,表示木板的長度。

輸出格式:

一個整數,不同的砍法數量。

樣例輸入

樣例輸出

6

6

樣例解釋:

1122,1212,1221,2112,2121,2211。

數據範圍:

對於100%的數據:1<=n<=2500。

打表大法好。或者你可以推通項公式。或者枚舉前兩個長度計算答案(這個比起推通項公式容易一點)。

總之,這道題的核心是,假設你取的四個木板長為a,b,c,d,它們能構成四邊形要滿足

a+b+c>d,a+b+d>c,a+c+d>b,b+c+d>a

我們可以發現a<n/2,b<n/2,c<n/2,d<n/2,就用這玩意去算答案

技術分享
#include<cstdio>
long long n;
int main(){
    //freopen("quad.in","r",stdin);freopen("quad.out","w",stdout);
    scanf("%lld",&n);
    printf("%lld",((n-3)*(n-2)*(n-1))/6-2*((n/2)*((n/2)-1)*((n/2)-2))/3);
    return 0;
}
View Code

生命不息刷題不止

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。

這道題不能貪心!這道題不能貪心!這道題不能貪心!重要的事情說三遍

3 10

3 5

2 5

2 5

貪心的答案是5,第2天做1,2兩題,第3天還債,第4天做第3題,第5天還債

而實際上只要4天,第2天做第1題,第3天做2,3兩題,第4天還債

正確思路是dp

設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。

20170924校內訓練