HIT训练营----1 题解
這次比賽地址在?http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=16641#overview
| Problem?A | URAL?1126 |
簽到題,注意這句話的意思就行了,Your?are?to?output?a?sequence?of?values?displayed?by?the?device.?The?first?number?of?the?sequence?is?the?maximal?element?of?the?first?Minput?numbers,?the?second?number?is?the?maximal?element?of?the?2nd,?…,?M+1-st?input?numbers?and?so?on.
再用單調(diào)遞減隊(duì)列保存前m項(xiàng)中的信息就行了
代碼如下:
#include <iostream> #include <cstdio> #include <cstring>using namespace std;const int X = 25005;struct node{int id,val; }q[X];int main(){//freopen("sum.in","r",stdin);int x,n;while(cin>>n){int h = 0,t = 0;int id = 0;while(scanf("%d",&x),x!=-1){id++;while(h<t&&q[h].id+n<=id)h++;while(h<t&&q[t-1].val<=x)t--;q[t].val = x;q[t].id = id;t++;if(id>=n)printf("%d\n",q[h].val);}}return 0; }| Problem?B | CodeForces?220B |
題目:
????給出n個(gè)數(shù),然后詢問區(qū)間[l,r]中滿足若數(shù)x出現(xiàn)過的次數(shù)為x的數(shù)的個(gè)數(shù)
?
分析:
由于題目n的范圍為1e5,所以最多只有450個(gè)數(shù)左右符合條件,首先把不符合條件的刪除,得到新的序列,然后可以用dp[i][j]先預(yù)處理出位置j中出現(xiàn)過了標(biāo)號為i的數(shù)的個(gè)數(shù)
?
代碼如下:
?
#include <cstdio> #include <cstring> #include <iostream> #include <vector> #include <algorithm>using namespace std;const int maxn = 500; const int maxm = 100005;int a[maxm],b[maxm],c[maxm][2],n,m; int dp[maxn][maxm]; vector<int> v;int main(){//freopen("sum.in","r",stdin);while(cin>>n>>m){for(int i=1;i<=n;i++){scanf("%d",&a[i]);b[i] = a[i];}sort(a+1,a+n+1);a[0] = -1;v.clear();int cnt = 0;memset(c,0,sizeof(c));for(int i=1;i<=n;i++){if(a[i]!=a[i-1])cnt++;c[cnt][0] = a[i];c[cnt][1]++;}for(int i=1;i<=cnt;i++)if(c[i][1]>=c[i][0])v.push_back(c[i][0]);int len = v.size();memset(dp,0,sizeof(dp));for(int i=0;i<len;i++){for(int j=1;j<=n;j++)if(v[i]==b[j])dp[i][j] = dp[i][j-1]+1;elsedp[i][j] = dp[i][j-1];}int x,y;while(m--){scanf("%d%d",&x,&y);int ans = 0;for(int i=0;i<len;i++)ans += (dp[i][y]-dp[i][x-1])==v[i];printf("%d\n",ans);}}return 0; }
?
?
| Problem?C | UVA?11624 |
?
題目:主要靠查代碼的編程能力(目測是所有題中第二個(gè)簡單題)
二維迷宮中,有一些著火點(diǎn)(可能不止一個(gè)),給出你的初始位置,人與著火點(diǎn)都是每秒鐘向相鄰的格子移動(dòng)一格,問人能不能夠在火勢到達(dá)之前走到邊界,如果能夠,輸出最短的時(shí)間
?
分析:
對于著火點(diǎn),可以預(yù)處理把所有的著火點(diǎn)都放進(jìn)隊(duì)列中(若是對于每個(gè)著火點(diǎn)都用BFS擴(kuò)展,必會TLE。。。),然后再用BFS處理出所有可燃燒的格子的最短到達(dá)時(shí)間。再用BFS來計(jì)算出人能夠達(dá)到邊界的最短時(shí)間。。。
?
我的代碼略挫
#include <cstdio> #include <cstring> #include <iostream>using namespace std;const int X = 1005;int dirx[] = {-1,1,0,0}; int diry[] = {0,0,-1,1};int n; int m; bool use[X][X]; int tt[X][X]; char map[X][X];struct node{int x,y,step;node(int _x,int _y,int _step){x = _x;y = _y;step = _step;} };struct point{int x,y,step;point(){}point(int _x,int _y,int _step){x = _x;y = _y;step = _step;} }q[X*X];bool out(int x,int y){return x>=n||y>=m||x<0||y<0; }int bfs(int sx,int sy){memset(use,false,sizeof(use));int head = 0;int tail = 0;q[tail++] = point(sx,sy,0);while(head<tail){point pre = q[head++];int x = pre.x;int y = pre.y;if(x==0||y==0||x==n-1||y==m-1)return pre.step;pre.step ++;for(int i=0;i<4;i++){int dx = dirx[i]+x;int dy = diry[i]+y;if(out(dx,dy))continue;if(use[dx][dy]||tt[dx][dy]<=pre.step||map[dx][dy]=='#')continue;use[dx][dy] = true;q[tail++] = point(dx,dy,pre.step);}}return -1; }void init(){memset(use,false,sizeof(use));int head = 0;int tail = 0;for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(map[i][j]=='F')q[tail++] = point(i,j,0);while(head<tail){point pre = q[head++];int x = pre.x;int y = pre.y;tt[x][y] = min(tt[x][y],pre.step ++);for(int i=0;i<4;i++){int dx = dirx[i]+x;int dy = diry[i]+y;if(out(dx,dy))continue;if(use[dx][dy]||map[dx][dy]=='#')continue;use[dx][dy] = true;q[tail++] = point(dx,dy,pre.step);}} }void solve(){cin>>n;cin>>m;for(int i=0;i<n;i++)scanf("%s",map[i]);memset(tt,0x3f,sizeof(tt));int sx,sy;sx = sy = 0;for(int i=0;i<n;i++)for(int j=0;j<m;j++)if(map[i][j]=='J'){sx = i;sy = j;}init();int ok = bfs(sx,sy);if(ok==-1)puts("IMPOSSIBLE");elseprintf("%d\n",ok+1); }int main(){//freopen("sum.in","r",stdin);int ncase;cin>>ncase;while( ncase-- != 0 )solve();return 0; }
| Problem?D | CodeForces?237E |
?
題目:給出一個(gè)文本串以及n個(gè)模式串,現(xiàn)在問存不存在從模式串中選擇一些字母使得能夠組成文本串,若能夠的話,輸出最小費(fèi)用(每個(gè)模式串的每個(gè)字母的費(fèi)用為第幾個(gè)模式串)。
?
分析:
最小費(fèi)用流,建立超級源點(diǎn)以及超級匯點(diǎn),對于文本串,統(tǒng)計(jì)每個(gè)字母出現(xiàn)的次數(shù),建立從源點(diǎn)到出現(xiàn)過的字母的有向邊,費(fèi)用為0,流量為該字母出現(xiàn)的次數(shù)。
再建立26個(gè)字母的中間節(jié)點(diǎn)。
對于模式串,建立n個(gè)節(jié)點(diǎn),用來限制每個(gè)模式串的最大刪除字母數(shù)目,對于每個(gè)模式串si,連上中間節(jié)點(diǎn)到他的有向邊,費(fèi)用為i,流量為該字母出現(xiàn)的次數(shù)。
然后讓這n個(gè)節(jié)點(diǎn)分別連上匯點(diǎn)的有向邊,流量為該模式串的出現(xiàn)次數(shù),費(fèi)用為0。
此致,費(fèi)用流建圖結(jié)束
(說的不是很好,具體看代碼)
#include <iostream> #include <cstdio> #include <cstring> #include <queue>using namespace std;const int X = 1005; const int maxn = 100005; const int maxm = 3000005; const int inf = 1e9; #define debug puts("here");int dis[maxn],pre[maxn],arc[maxn]; int po[maxn],tol; bool use[maxn]; int map[X][X]; int n,m,s,t,k,p,ans; int d[maxn]; int num[30];struct node{int y,f,c,next; }edge[maxm];void add(int x,int y,int c,int f){edge[++tol].y = y;edge[tol].c = c;edge[tol].f = f;edge[tol].next = po[x];po[x] = tol;edge[++tol].y = x;edge[tol].c = -c;edge[tol].f = 0;edge[tol].next = po[y];po[y] = tol; }bool spfa(){memset(use,false,sizeof(use));for(int i=1;i<=n;i++)dis[i] = inf;dis[s] = 0;queue<int> q;q.push(s);pre[s] = 0;int x,y;while(q.size()){x = q.front();q.pop();use[x] = false;for(int i=po[x];i;i=edge[i].next){y = edge[i].y;if(edge[i].f>0&&edge[i].c+dis[x]<dis[y]){dis[y] = edge[i].c + dis[x];pre[y] = i;if(!use[y]){use[y] = true;q.push(y);}}}}if(dis[t]==inf)return false;int aug = inf;for(int i=pre[t];i;i=pre[edge[i^1].y])aug = min(aug,edge[i].f);for(int i=pre[t];i;i=pre[edge[i^1].y]){edge[i].f -= aug;edge[i^1].f += aug;}ans += dis[t]*aug;return true; }int main(){//freopen("sum.in","r",stdin);char str[105];while(cin>>str>>n){memset(po,0,sizeof(po));tol = 1;int sum = 0;memset(num,0,sizeof(num));int len = strlen(str);for(int i=0;i<len;i++)num[str[i]-'a'+1] ++;s = 26+n+1;t = s+1;for(int i=1;i<=26;i++){add(s,i,0,num[i]);sum += num[i];}int x;for(int i=1;i<=n;i++){scanf("%s%d",str,&x);memset(num,0,sizeof(num));for(int j=0;str[j];j++)num[str[j]-'a'+1] ++;for(int j=1;j<=26;j++)if(num[j])add(j,i+26,i,num[j]);add(i+26,t,0,x);}n = t;ans = 0;int ok = 0;while(spfa());for(int i=po[t];i;i=edge[i].next)ok += edge[i].f;if(ok!=sum)puts("-1");elsecout<<ans<<endl;}return 0; }
?
| Problem?E | UVA?11324 |
?
題目:
經(jīng)典圖論模型,求某個(gè)點(diǎn)集,使得點(diǎn)集中任意兩個(gè)點(diǎn)至少有一條可達(dá)邊(u可到達(dá)v,或者v可以到達(dá)u),求點(diǎn)集的最大數(shù)目
?
分析:
????強(qiáng)連通分量求GCC,然后構(gòu)造出新圖,新圖是一個(gè)dag,對于dag上用dp求出最長路徑即可。DP轉(zhuǎn)移方程為dp[x]?=?size[x]?+?max(dp[y]);?縮點(diǎn)后有邊x到y的邊,記憶化搜索就行了,具體看實(shí)現(xiàn)代碼
?
#include <iostream>#include <cstring>#include <cstdio>#include <vector>using namespace std;const int maxn = 1005;const int maxm = 50005;#define debug puts("here");int dfn[maxn],low[maxn],stack[maxn],father[maxn],bcnt,top,depth;bool instack[maxn];int po[maxn],tol,n,m;int id[maxn];int dp[maxn];int sum[maxn];vector<int> vec[maxn];struct node{int y,next;}edge[maxm];void add(int x,int y){edge[++tol].y = y;edge[tol].next = po[x];po[x] = tol;}void dfs(int x){ //遞歸實(shí)現(xiàn)tarjan算法low[x] = dfn[x] = ++depth;instack[x] = true;stack[++top] = x;int y;for(int i=po[x];i;i=edge[i].next){y = edge[i].y;if(!dfn[y]){dfs(y);low[x] = min(low[x],low[y]);}else if(instack[y])low[x] = min(low[x],dfn[y]);}if(low[x]==dfn[x]){++bcnt;do{y = stack[top--];instack[y] = false;father[y] = bcnt;}while(x!=y);}}void tarjan(){memset(low,0,sizeof(low));memset(dfn,0,sizeof(dfn));top = bcnt = depth = 0;for(int i=1;i<=n;i++)if(!dfn[i])dfs(i);}int f(int x){ //記憶化方法求dag上的最長路徑if(dp[x])return dp[x];int ans = 0;for(int i=0;i<(int)vec[x].size();i++){ //從x的所有邊出發(fā),求出最大的路徑int y = vec[x][i];ans = max(ans,f(y)); //轉(zhuǎn)移方程}dp[x] = ans+sum[x];return dp[x];}void dag(){memset(id,0,sizeof(id));memset(sum,0,sizeof(sum));memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++)vec[i].clear();for(int x=1;x<=n;x++){ //構(gòu)造新圖for(int j=po[x];j;j=edge[j].next){int y = edge[j].y;if(father[x]!=father[y]){vec[father[x]].push_back(father[y]);id[father[y]] ++;}}sum[father[x]] ++; //統(tǒng)計(jì)每個(gè)縮點(diǎn)后的該節(jié)點(diǎn)所包含的所有原圖的節(jié)點(diǎn)數(shù)目}int ans = 0;for(int i=1;i<=bcnt;i++)if(!id[i])ans = max(f(i),ans);cout<<ans<<endl;}int main(){//freopen("sum.in","r",stdin);int ncase;cin>>ncase;while(ncase--){cin>>n>>m;int x,y;memset(po,0,sizeof(po));tol = 0;while(m--){scanf("%d%d",&x,&y);add(x,y);}tarjan();dag();}return 0;}
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/yejinru/archive/2012/11/10/2764066.html
總結(jié)
以上是生活随笔為你收集整理的HIT训练营----1 题解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: eclipse 项目 无法 rename
- 下一篇: Hit or Miss