TYZ群賽 8/21解題報告
TYZ 8/21群賽 解題報告
賽制:OI
難度:約等於NOIP
題目來自網路::
下面有詳細的解說
T1
T1
竊賊和火柴
【問題描述】
一個竊賊進入了火柴倉庫,想要偷儘可能多的火柴。倉庫裡有 m 個集裝箱,
第 i 個集裝箱裡有 a
i 個火柴盒,每個火柴盒裡有 b
i 根火柴。所有火柴盒大小相同。
竊賊的帆布揹包恰能容納 n 個火柴盒。你的任務是找出竊賊能拿走的火柴的最大
數量。他沒時間重新調整火柴盒中的火柴,這就是他只是挑選不超過 n 個其包含
火柴數之和最大的火柴盒的原因。
【輸入檔案】
輸入檔案 bam.in 第一行包含整數 n(1≤n≤2·10
8
)和整數 m(1≤m≤20)。
第 i+1 行包含一對整數 a
i 和 b
i (1≤a
i≤10 8,1≤bi≤10)。所有輸入的數字都是整
數。
【輸出檔案】
輸出檔案 bam.out 包含唯一一個整數代表問題的答案。
【輸入樣例 1】
7 3
5 10
2 5
3 6
【輸出樣例 1】
62
【輸入樣例 2】
3 3
1 3
2 2
3 1
【輸出樣例 2】
7
這道題目的相似型應該是一次USACO的一道題:混合牛奶1
不過不用在意這些細節啦
這個題秒懂的貪心,先排序,選取容量最大的火柴盒子先進行拿,直到揹包裝滿為止.
程式碼實現方面,需要注意的是裝滿揹包時候的減法
不過還是10多分鐘就幹掉了;
程式碼如下:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<math.h> using namespace std; typedef long long ll;//這句是用來ll表示long long的數的 struct bx{ ll a,b; }; bx r[25]; ll n,m,k; ll ans; int cmp(bx x,bx y) { return x.b>y.b; } int main() { freopen("bam.in","r",stdin); freopen("bam.out","w",stdout); cin>>n>>m; for(ll i=1;i<=m;i++) { cin>>r[i].a>>r[i].b; } sort(r+1,r+1+m,cmp); ll nw=n; for(ll i=1;i<=m;i++) { if(nw>r[i].a) { nw-=r[i].a; ans+=r[i].a*r[i].b; } else { ans+=nw*r[i].b; break; } } cout<<ans<<endl; return 0; }
第二題’:
名字叫“第三題”(。。。。。。。。。。。。。。)
原型是POJ的2161
Lamps-O-Matic 公司裝修很大的吊燈。吊燈由幾層組成。(從下至上)第一層
的水晶燈直接掛在環上。把環集起來以後再掛到上一層的環上面,依此類推。最
後一層是一個掛滿了燈和小環的大環(廢話)。
現在由機器人來做掛燈的事。機器人身上有資源補給,掛燈的時候,它使用
一個棧來儲存燈和環。一開始,這個棧是空的。機器人執行一個指令集來運作。
這個指令集是一個字串。
舉例說明:aaaaa3aaa2aaa45。a 代表將小燈放入棧中。數字 N 代表將目前棧
頂向下的 N 個資源取出,組成一個環,然後放回棧頂。整個棧的流程如下。
aaaaa → aa[aaa] → aa[aaa]aaa → aa[aaa]a[aa] → aa[aaa]a[aa]aaa →
aa[aaa]a[[aa]aaa]→END
這樣就需要棧空間的最大值為8,當其狀態為 aa[aaa]a[aa]aaa 時就需要,注
意:環和燈都算一個。
然而還有一個問題。機器人的棧不夠大了(真是次品)。所以需要你編一個
指令,使吊燈的設計不變,讓指令所需的棧空間越小越好。所謂的設計不變,就
是指:假設在同一層環原來有4 個部件,1234,那麼1234、4123、3412等等,只要環的順序不變就可以。
但是不能有部件增加或者減少。
【輸入檔案】
輸入檔案 three.in 每一行一個字串,代表指令。
【輸出檔案】
輸出檔案為three.out 包含一行,代表需要的棧空間
【輸入樣例】
aaaaa3aaa2aaa45
【輸出樣例】
6
【資料規模】
100%的資料字串長度≤10^4
想到了啥呢,剛開始的時候想到:
1. 可以貪心地放置,每次都先把成環的放進去,壓縮成環之後就可以省空間啊
2. 能先放大環就不要先放小環
3. 然而他是有順序的
4. 這道題目有些尷尬
那就繼續想了:
假設一個環子的掛的每個小環子都達到最優解,那麼這個環子就達到最優解。
換言之,只要計算出了每個環子的最優解,就可以計算出最優解。
第二,每個環子最多有9個子環
那就愉快的分治吧!
對於每個環,貪心和列舉差不了多少,貪心還不一定對,所以就列舉從環的哪個位置開始組裝吧
這個字串給得。。。。讓程式碼實現變得不是很簡單啊
我總不能用括號序列吧歪歪歪,那麼怎麼辦呢
可以不可以先找到數字,把串裡面的先字母后數字的順序調換一下。
有難度,為何不直接從後面……對,就從字串的菊花開始。
每次從後面找到數字之後就處理,用深度優先的遞迴來處理就好了。
經過兩個小時的修改,第二題就完工了。
#include<iostream>
#include<limits.h>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=10005;
struct pao{int fi,ls;
};
char s[maxn];
int n,m,k;
pao kong;
pao cal(int cur)
{
pao res=kong;
int nw=s[cur]-'0';
int w=0;
vector<int> po;
for(int i=cur-1;;)
{
if(w==nw)
{
res.ls=i;
break;
}
if(s[i]=='a')
{
w++;
i--;
po.push_back(1);
continue;
}
if(s[i]>='0'&&s[i]<='9')
{
pao wi=cal(i);
i=wi.ls;
po.push_back(wi.fi);
w++;
}
}
int len=po.size();
int tem=INT_MAX;
/*
cout<<"each line 's results:"<<endl;
for(int i=0;i<len;i++)
cout<<po[i]<<" ";
cout<<endl;
*/
stack<int> hel;
for(int i=0;i<len;i++)
{
hel.push(po[i]);
}
for(int i=0;i<len;i++)
{
int zc=hel.top();
po[i]=zc;
hel.pop();
}
/*
cout<<"each line 's results:"<<endl;
for(int i=0;i<len;i++)
cout<<po[i]<<" ";
cout<<endl;
*/
for(int i=0;i<len;i++)
{
int sum=0;
int tm=0;
bool shou=1;
for(int j=INT_MAX;j!=i;)
{
if(shou)
{
j=i;
shou=0;
}
tm=max(tm,po[j]+sum);
sum++;
j=(j+1)%len;
}
tem=min(tem,tm);
}
res.fi=tem;
//cout<<"but the final results is :"<<tem<<endl;
return res;
}
int sz=1;
int main()//請養成從主函式開始閱讀的好習慣!
{
freopen("three.in","r",stdin);
freopen("three.out","w",stdout);
while(cin>>s[sz])
sz++;
pao ans=cal(sz-1);
cout<<ans.fi<<endl;
return 0;
}
註釋:
我是不會壓位的那種人,所以我就寫了結構體
所以說分治的返回值就比較挫
然後我是那種陣列運用不太熟練的人,於是我把字串反過來的時候就用了
出錯的地方:
1. 開始的時候sz這個輸入的游標就輸錯了應該從sz-1開始遞迴的,很尷尬
2. 然後開始的時候,在列舉環的位置的時候,雖然用了%,還是出錯,對於for迴圈的掌握不熟,所以導致gg
3. 我個強迫症,定義變數j之後不知道這玩意等不等於i,就設定成了0,然後完美wa了10分鐘。(設定成-1不就行了嘛,然後我就設成了INT_MAX)
4. 樣例開始的時候一直是5,後來發現是爆字串菊花然後vector的位置忘了翻過來,導致失誤。
把字串翻過之後就停手了,因為時間不多瞭然後我去敲第三題的暴力。
調整
【問題描述】
已給定一個 N 個點 M 條邊的有向圖,點編號為 1 到 N,第 i 條邊為(UI,vi)
權值為 wi。你可以進行一次操作,使得任意一條邊的權值變成任意非負整數。要
求進行儘量少的操作次數,使得點 1 到點 N 的最短路徑長度變成 c。
題目保證,c 小於在未進行任何操作之前的原圖中 1 到 N 的最短路長度。
【輸入檔案】
輸入檔案 tweak.in 第一行三個整數,N,M 和 c
接下來 M 行,每行一條邊的資訊(UI,vi)
和 wi,第 i 行的表述第 i 條邊的資訊。
保證不會有自環存在,對於不同的 i 和 j,
(ui,vi)不同於(uj,vj) 。
【輸出檔案】
輸出檔案 tweak.out 一行一個整數,要進行最少多少次操作才能使得最短路
長度變為 c。
【輸入樣例】
3 3 3
1 2 3
2 3 3
1 3 8
【輸出樣例】
1
【樣例說明】
將邊 1,3 的權值修改為 2 就可以了。
【資料規模】
N≤100
M≤1000
0≤c≤100000
0≤wi≤10000
30%資料滿足 M≤20
50%的資料滿足 M≤70
以為自己這次模擬賽又要墊底了,當時想死的心都有了,電光火石之間突然第二題瞬間就有把握了?!,整個人都沸騰了!
只剩十分鐘了,抄起傢伙,準備暴力,思路就是dfs出來所有路徑,然後計算需要的減去的次數,記錄路徑用模擬棧和回溯
如期交上暴力40/100
暴力程式碼如下,好像不太對,wa了一個,剩下的都是re
註釋:
我是不會壓位的那種人,所以我就寫了結構體
所以說分治的返回值就比較挫
然後我是那種陣列運用不太熟練的人,於是我把字串反過來的時候就用了
出錯的地方:
1. 開始的時候sz這個輸入的游標就輸錯了應該從sz-1開始遞迴的,很尷尬
2. 然後開始的時候,在列舉環的位置的時候,雖然用了%,還是出錯,對於for迴圈的掌握不熟,所以導致gg
3. 我個強迫症,定義變數j之後不知道這玩意等不等於i,就設定成了0,然後完美wa了10分鐘。(設定成-1不就行了嘛,然後我就設成了INT_MAX)
4. 樣例開始的時候一直是5,後來發現是爆字串菊花然後vector的位置忘了翻過來,導致失誤。
把字串翻過之後就停手了,因為時間不多瞭然後我去敲第三題的暴力。
調整
【問題描述】
已給定一個 N 個點 M 條邊的有向圖,點編號為 1 到 N,第 i 條邊為(UI,vi)
權值為 wi。你可以進行一次操作,使得任意一條邊的權值變成任意非負整數。要
求進行儘量少的操作次數,使得點 1 到點 N 的最短路徑長度變成 c。
題目保證,c 小於在未進行任何操作之前的原圖中 1 到 N 的最短路長度。
【輸入檔案】
輸入檔案 tweak.in 第一行三個整數,N,M 和 c
接下來 M 行,每行一條邊的資訊(UI,vi)
和 wi,第 i 行的表述第 i 條邊的資訊。
保證不會有自環存在,對於不同的 i 和 j,
(ui,vi)不同於(uj,vj) 。
【輸出檔案】
輸出檔案 tweak.out 一行一個整數,要進行最少多少次操作才能使得最短路
長度變為 c。
【輸入樣例】
3 3 3
1 2 3
2 3 3
1 3 8
【輸出樣例】
1
【樣例說明】
將邊 1,3 的權值修改為 2 就可以了。
【資料規模】
N≤100
M≤1000
0≤c≤100000
0≤wi≤10000
30%資料滿足 M≤20
50%的資料滿足 M≤70
以為自己這次模擬賽又要墊底了,當時想死的心都有了,電光火石之間突然第二題瞬間就有把握了?!,整個人都沸騰了!
只剩十分鐘了,抄起傢伙,準備暴力,思路就是dfs出來所有路徑,然後計算需要的減去的次數,記錄路徑用模擬棧和回溯
如期交上暴力40/100
暴力程式碼如下,好像不太對,wa了一個,剩下的都是re
註釋:
我是不會壓位的那種人,所以我就寫了結構體
所以說分治的返回值就比較挫
然後我是那種陣列運用不太熟練的人,於是我把字串反過來的時候就用了
出錯的地方:
1.開始的時候sz這個輸入的游標就輸錯了應該從sz-1開始遞迴的,很尷尬
2.然後開始的時候,在列舉環的位置的時候,雖然用了%,還是出錯,對於for迴圈的掌握不熟,所以導致gg
3.我個強迫症,定義變數j之後不知道這玩意等不等於i,就設定成了0,然後完美wa了10分鐘。(設定成-1不就行了嘛,然後我就設成了INT_MAX)
4.樣例開始的時候一直是5,後來發現是爆字串菊花然後vector的位置忘了翻過來,導致失誤。
把字串翻過之後就停手了,因為時間不多瞭然後我去敲第三題的暴力。
調整
【問題描述】
已給定一個 N個點 M 條邊的有向圖,點編號為 1 到 N,第 i條邊為(UI,vi)
權值為 wi。你可以進行一次操作,使得任意一條邊的權值變成任意非負整數。要
求進行儘量少的操作次數,使得點 1到點 N 的最短路徑長度變成 c。
題目保證,c小於在未進行任何操作之前的原圖中 1 到 N 的最短路長度。
【輸入檔案】
輸入檔案 tweak.in第一行三個整數,N,M 和 c
接下來 M行,每行一條邊的資訊(UI,vi)
和 wi,第 i行的表述第 i 條邊的資訊。
保證不會有自環存在,對於不同的 i和 j,
(ui,vi)不同於(uj,vj) 。
【輸出檔案】
輸出檔案 tweak.out一行一個整數,要進行最少多少次操作才能使得最短路
長度變為 c。
【輸入樣例】
3 3 3
1 2 3
2 3 3
1 3 8
【輸出樣例】
1
【樣例說明】
將邊 1,3的權值修改為 2 就可以了。
【資料規模】
N≤100
M≤1000
0≤c≤100000
0≤wi≤10000
30%資料滿足 M≤20
50%的資料滿足 M≤70
以為自己這次模擬賽又要墊底了,當時想死的心都有了,電光火石之間突然第二題瞬間就有把握了?!,整個人都沸騰了!
只剩十分鐘了,抄起傢伙,準備暴力,思路就是dfs出來所有路徑,然後計算需要的減去的次數,記錄路徑用模擬棧和回溯
如期交上暴力40/100
暴力程式碼如下,好像不太對,wa了一個,剩下的都是re
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
struct ed{
int u,v,w;
};
ed a[1005];
int e[105][105];
int t1,t2,t3;
int st[1105];
int tp;
int n,m,c;
int ANS=INT_MAX;
void dfs(int x)
{
if(x==n)
{
priority_queue<int> p;
int sum=0;
for(int i=0;i<tp;i++)
{
p.push(st[i]);
sum+=st[i];
}
int ned=sum-c;
int ans=0;
while(ned>0)
{
int nw=p.top();
p.pop();
if(nw<ned)
{
ned-=nw;
ans++;
}
else
{
ned=0;
ans++;
ANS=min(ANS,ans);
return;
}
}
}
for(int i=1;i<=n;i++)
{
if(e[x][i])
{
st[tp]=e[x][i];
tp++;
dfs(i);
tp--;
}
}
}
int main()
{
freopen("tweak.in","r",stdin);
freopen("tweak.out","w",stdout);
cin>>n>>m>>c;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&t1,&t2,&t3);
e[t1][t2]=t3;
}
dfs(1);
cout<<ANS<<endl;
return 0;
}
正解在下面
#include<cstdio>
#include<cstring>
#include<climits>
#include<iostream>
using namespace std;
int n,m,c,cur[111],num,t1,t2,t3;
int l,r,d[104][100111],ans;
struct edge{int to,v,frh;}a[50001];
struct queue{int z,y;}q[5000001];
int main(){
scanf("%d%d%d",&n,&m,&c);
for (int i=1; i<=n; i++)
{
cur[i]=i;
}
num=n;
for (int i=1; i<=m; i++)
{
scanf("%d%d%d",&t1,&t2,&t3);
num++; a[num].to=t2; a[num].v=t3; a[cur[t1]].frh=num; cur[t1]=num;
}
memset(d,-1,sizeof d);
l=r=1; q[1].z=1; q[l].y=0;d[1][0]=0;//
while (l<=r)
{
int t=q[l].z;
while (a[t].frh!=0)
{
t=a[t].frh;
//尋找來邊
int nz=q[l].z;
int ny=q[l].y;
int nv=a[t].v;
int nd=d[nz][ny];
int nx=d[a[t].to][q[l].y+a[t].v];
if (nz+nv<=c &&
(nd<nx||nx==-1))
{
nx=nd;
r++; q[r].z=a[t].to; q[r].y=q[l].y+a[t].v;
}
//由於上一步修改了部分,所有的變數重新定義(反正複製貼上)
nz=q[l].z;
ny=q[l].y;
nv=a[t].v;
nd=d[nz][ny];
nx=d[a[t].to][q[l].y+a[t].v];
int ns=d[q[l].z][q[l].y];
int nm=d[a[t].to][q[l].y];
if (ns+1<nm||nm==-1)
{
d[a[t].to][q[l].y]=nm=ns+1;
r++; q[r].z=a[t].to; q[r].y=q[l].y;
}
}
l++;
}
ans=INT_MAX;
for (int i=0; i<=c; i++)
if (d[n][i]<ans && d[n][i]!=-1)
ans=d[n][i];
cout<<ans<<endl;
return 0;
}
總分:
1 100/100
2 100/100
3 40/100