2016CCPC東北地區大學生程式設計競賽 - 重現賽
A 題目連線:HDU 5922 Minimum’s Revenge
水題,每次連線上1就行,就是一個等差數列。
#include<iostream> #include<algorithm> #include<cstring> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<map> #include<set> #include<stack> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; #define bug printf("*********\n"); #define debug(x) cout<<"["<<x<<"]" <<endl; #define mid (l+r)/2 #define chl 2*k+1 #define chr 2*k+2 #define lson l,mid,chl #define rson mid,r,chr #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)); const long long mod=1e9+7; const int maxn=5e5+5; const int INF=0x7fffffff; const int inf=0x3f3f3f3f; const double eps=1e-8; int main() { int n,t,cas=1; scanf("%d",&t); while(t--){ scanf("%d",&n); ll res=n; printf("Case #%d: %lld\n",cas++,(res+2)*(res-1)/2); } return 0; }
B 題目連結:HDU 5923 Prediction
題意:一棵樹,每個點代表一條邊,每次選擇幾個點,需要把他的祖先也選上,然後把圖裡面相應的邊連線上,問連線後的圖有多少個聯通塊。
題解:可持續化並查集,每個頂點開一個並查集,維護從根節點到當前節點已經連線的圖,再把自己這條邊連上。
查詢,把所有點的並查集合並一下就可以,然後輸出合併後並查集塊的個數。
#include<bits/stdc++.h> using namespace std; const int maxn=5e2+2; const int maxm=1e4+5; bool u[maxm]; int par[maxm][maxn]; struct node { int x,y; int fa; } tree[maxm]; int n,m; int find(int y,int x) { return par[y][x]==x?x:par[y][x]=find(y,par[y][x]); } void dfs(int x) { int fa=tree[x].fa; u[x]=1; if(u[fa]==0) { dfs(fa); } else { if(x==1) { // cout<<"1asd"<<endl; for(int i=0; i<=n; i++)par[1][i]=i; par[1][tree[x].x]=tree[x].y; } else { for(int i=0; i<=n; i++)par[x][i]=par[fa][i]; int X=find(x,tree[x].x),Y=find(x,tree[x].y); if(X!=Y) { par[x][X]=par[x][Y]; } } } } int main() { int t,cas=1; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) { if(i==1)tree[i].fa=1; else { int x; scanf("%d",&x); tree[i].fa=x; } } for(int i=1; i<=m; i++) { u[i]=0; scanf("%d%d",&tree[i].x,&tree[i].y); } for(int i=1; i<=m; i++) { if(!u[i]) { dfs(i); } } int q; scanf("%d",&q); printf("Case #%d:\n",cas++); while(q--) { int k,s; scanf("%d",&k); int res=0; for(int i=0; i<=n; i++)par[0][i]=i; while(k--) { scanf("%d",&s); // for(int i=1; i<=n; i++)printf("%d ",par[s][i]); for(int i=1; i<=n; i++) { int t1=find(0,i),t2=find(s,i); if(t1!=t2) { int t3=find(0,t2); if(t3!=t1) { res++; par[0][t1]=par[0][t3]; } } } } printf("%d\n",n-res); } } return 0; }
C 題目連線:HUD 5924 Mr. Frog’s Problem
A/B+ B/A 只有在兩個數最接近的時候最小,所以如果A<=C<D<=B,C /D+D/C必定小於於等 A/B+B/A所以只有和A B相同的時候才會滿足條件。
#include<iostream> #include<algorithm> #include<cstring> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<map> #include<set> #include<stack> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; #define bug printf("*********\n"); #define debug(x) cout<<"["<<x<<"]" <<endl; #define mid (l+r)/2 #define chl 2*k+1 #define chr 2*k+2 #define lson l,mid,chl #define rson mid,r,chr #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)); const long long mod=1e9+7; const int maxn=5e5+5; const int INF=0x7fffffff; const int inf=0x3f3f3f3f; const double eps=1e-8; ll a,b,t,n; int main() { int cas=1; cin>>t; while(t--) { cin>>a>>b; printf("Case #%d:\n",cas++); if(a==b) { puts("1"); cout<<a<<" "<<b<<endl; } else { puts("2"); cout<<a<<" "<<b<<endl; cout<<b<<" "<<a<<endl; } } return 0; }
D 題目連線:HDU 5925 Coconuts
題意:給你一個R*C的矩陣中間有幾個n個點,問分成了幾個聯通塊,聯通塊的大小是多少。
題解:R,C範圍是1e9肯定是要離散,離散之後變成了一個不到 2000*2000的矩陣,求聯通塊數量直接DFS一遍就可以了。
問題來了了,離散之後怎麼求每個塊的大小呢。
首先你是根據行和列分別離散,計算主要是把離散掉的重新算回來。
如下圖加入黃色是你被覆蓋的格子,你會把橫著離散黑色的格子為一個格子,紅色的豎著離散成一個格子。因此,你只要把這些離散的格子從新加回來就行了,另外還要加上中間那一塊被離散掉的。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
#define bug printf("*********\n");
#define debug(x) cout<<"["<<x<<"]" <<endl;
#define mid (l+r)/2
#define chl 2*k+1
#define chr 2*k+2
#define lson l,mid,chl
#define rson mid,r,chr
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a));
const long long mod=1e9+7;
const int maxn=205;
const int INF=0x7fffffff;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
int n;
map<int,int> mpx,mpy;
int x[maxn],y[maxn];
int lx[maxn],ly[maxn];
ll vx[maxn*10],vy[maxn*10];
int mp[maxn*10][maxn*10],mx,my;
int dx[]= {-1,0,1,0},dy[]= {0,-1,0,1};
ll ans[maxn*10];
void dfs(int tx,int ty,int pos) {
if(mp[tx][ty]!=0)return ;
mp[tx][ty]=pos;
++ans[pos];
for(int i=0; i<4; i++) {
int ttx=tx+dx[i],tty=ty+dy[i];
if(ttx>0&&ttx<=mx&&tty>0&&tty<=my) {
dfs(ttx,tty,pos);
}
}
}
int main() {
int cas=1,t;
// freopen("in.txt","r",stdin);
scanf("%d", &t);
while(t--) {
mpx.clear();
mpy.clear();
mem(ans,0);
int r,c;
scanf("%d%d",&r,&c);
scanf("%d",&n);
for(int i=0; i<n; i++) {
scanf("%d%d",&x[i],&y[i]);
lx[i]=x[i];
ly[i]=y[i];
}
lx[n]=r;
sort(lx,lx+n+1);
int d=0;
vx[d]=0;
for(int i=0; i<=n; i++) {
if(lx[i]==vx[d])continue;
else if(lx[i]==vx[d]+1) {
vx[d+1]=vx[d]+1;
mpx[lx[i]]=d+1;
d+=1;
} else if(lx[i]-d==2) {
vx[d+1]=vx[d]+1;
vx[d+2]=vx[d]+2;
mpx[lx[i]]=d+2;
d+=2;
} else {
vx[d+1]=vx[d]+1;
vx[d+2]=lx[i];
mpx[lx[i]]=d+2;
d+=2;
}
}
ly[n]=c;
sort(ly,ly+n+1);
mx=d;
d=0;
vy[d]=0;
for(int i=0; i<=n; i++) {
if(ly[i]==vy[d])continue;
else if(ly[i]==vy[d]+1) {
vy[d+1]=vy[d]+1;
mpy[ly[i]]=d+1;
d+=1;
} else if(ly[i]-d>=2) {
vy[d+1]=vy[d]+1;
vy[d+2]=ly[i];
mpy[ly[i]]=d+2;
d+=2;
}
}
my=d;
mem(mp,0);
for(int i=0; i<n; i++) {
mp[mpx[x[i]]][mpy[y[i]]]=-1;
}
int num=1;
for(int i=1; i<=mx; i++) {
for(int j=1; j<=my; j++) {
if(mp[i][j]==0) {
dfs(i,j,num++);
}
}
}
for(int j=1; j<=my; j++) { //把離散豎著的加起來
for(int i=1; i<=mx; i++) {
if(mp[i][j]!=-1) {
ans[mp[i][j]]+=vx[i]-vx[i-1]-1;
} else if(mp[i-1][j]!=-1) {
ans[mp[i-1][j]]+=vx[i]-vx[i-1]-1;
}
}
}
for(int i=1; i<=mx; i++) { //把橫著離散掉的加起來
for(int j=1; j<=my; j++) {
if(mp[i][j]!=-1) {
ans[mp[i][j]]+=vy[j]-vy[j-1]-1;
} else if(mp[i][j-1]!=-1) {
ans[mp[i][j-1]]+=vy[j]-vy[j-1]-1;
}
}
}
for(int i=1; i<=mx; i++) { //把中間那塊離散掉的加起來
for(int j=1; j<=my; j++) {
if(mp[i][j]!=-1) {
ans[mp[i][j]]+=(vy[j]-vy[j-1]-1)*(vx[i]-vx[i-1]-1);
} else if(mp[i-1][j-1]!=-1) {
ans[mp[i-1][j-1]]+=(vy[j]-vy[j-1]-1)*(vx[i]-vx[i-1]-1);
}
}
}
printf("Case #%d:\n%d\n",cas++,num-1);
sort(ans+1,ans+num);
for(int i=1; i<num; i++) {
printf("%lld",ans[i]);
if(i+1==num)printf("\n");
else printf(" ");
}
}
return 0;
}
下面是2組資料,正確答案能手算出來
/*
2
100 100
20
1 50
1 51
1 55
1 60
2 50
2 54
2 56
2 60
3 50
3 51
3 55
3 60
4 51
4 52
4 53
4 54
4 56
4 57
4 58
4 59
100 100
8
1 2
2 1
100 99
99 100
99 1
100 2
1 99
2 100
*/
E:題目連結 HDU 5926 Mr. Frog’s Game
水題不解釋了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
#define bug printf("*********\n");
#define debug(x) cout<<"["<<x<<"]" <<endl;
#define mid (l+r)/2
#define chl 2*k+1
#define chr 2*k+2
#define lson l,mid,chl
#define rson mid,r,chr
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a));
const long long mod=1e9+7;
const int maxn=5e5+5;
const int INF=0x7fffffff;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
int ar[35][35];
int n,m;
int dir[4][2]={1,0,0,1,-1,0,0,-1};
int main() {
int cas=1,t;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
for(int i=0;i<n;++i){
for(int j = 0; j < m; ++j){
scanf("%d", &ar[i][j]);
}
}
int flag = 0;
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
for(int k=0;k<4;++k){
int px = i + dir[k][0],py = j + dir[k][1];
if(px<0||py<0||px>=n||py>=m)continue;
if(ar[px][py]==ar[i][j]){
flag=1;break;
}
}
if(flag)break;
}
if(flag)break;
}
for(int i=0;i<n;++i){
for(int j=i+1;j<n;++j){
if(ar[i][0]==ar[j][0]||ar[i][m-1]==ar[j][m-1]){
flag=1;break;
}
}
if(flag)break;
}
for(int i=0;i<m;++i){
for(int j=i+1;j<m;++j){
if(ar[0][i]==ar[0][j]||ar[n-1][i]==ar[n-1][j]){
flag=1;break;
}
}
if(flag)break;
}
printf("Case #%d: ",cas++);
if(flag)printf("Yes\n");
else printf("No\n");
}
return 0;
}
F 題目連結:HDU 5927 Auxiliary Set
題意:隨便選幾個點作為不重要的點,其他的全是重要的點,然後把不重要的點中如果是兩個不同節點的最近公共祖先就把他變為重要的點,問,選了幾個不重要的點,最後重要的點總共有多少個。
題解:資料看的挺嚇人的 1e3 組 1e5的資料那命去寫啊,實際上沒多少。。。。。直接按不重要的點深度排個序,如果是另外兩個重要的點的LCA就變成重要的點。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
#define bug printf("*********\n");
#define debug(x) cout<<"["<<x<<"]" <<endl;
#define mid (l+r)/2
#define chl 2*k+1
#define chr 2*k+2
#define lson l,mid,chl
#define rson mid,r,chr
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a));
const long long mod=1e9+7;
const int maxn=1e5+5;
const int INF=0x7fffffff;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
int n,m;
struct edge {
int to,next;
} eg[maxn*2];
int head[maxn],tot;
void init() {
mem(head,-1);
tot=0;
}
void add(int u,int v) {
eg[tot].to=v;
eg[tot].next=head[u];
head[u]=tot++;
}
int dep[maxn],pre[maxn];
int u[maxn];
int res[maxn];
int num[maxn];
int dfs(int r,int p,int d) {
dep[r]=d;
pre[r]=p;
int ans=0;
for(int i=head[r]; i!=-1; i=eg[i].next) {
if(eg[i].to!=p) {
ans+=dfs(eg[i].to,r,d+1);
}
}
num[r]=ans;
return ans;
}
void read(int &sum) {
scanf("%d",&sum);
return ;
sum=0;
int flag=0;
char ch=getchar();
while(!(ch>='0'&&ch<='9')) {
if (ch == '-') {
flag = 1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=getchar();
if(flag)sum*=-1;
}
bool cmp(int &a,int &b) {
return dep[a]>dep[b];
}
int main() {
int t,cas=1;
scanf("%d",&t);
while(t--) {
read(n);
read(m);
init();
for(int i=0; i<n-1; i++) {
int a,b;
read(a);
read(b);
add(a,b);
add(b,a);
}
dfs(1,-1,1);
printf("Case #%d:\n",cas++);
while(m--) {
int k,d,ans=0;
read(k);
ans=n-k;
for(int i=0; i<k; i++) {
read(res[i]);
u[res[i]]=-1;
}
sort(res,res+k,cmp);
for(int i=0; i<k; i++) {
d=0;
for(int j=head[res[i]]; j!=-1; j=eg[j].next) {
int to=eg[j].to;
if(to==pre[res[i]]) {
continue;
} else {
if(u[to]<0) {
continue;
}
if(u[res[i]]==-1) {
u[res[i]]=1;
} else u[res[i]]++;
if(u[res[i]]==2) {
ans++;
break;
}
}
}
}
for(int i=0; i<k; i++)u[res[i]]=0;
printf("%d\n",ans);
}
}
return 0;
}
H 題目連線:HDU 5929 Basic Data Structure
簡單模擬一下就可以了,記錄下一最後一個零的位置,因為到零除了是第一個位置之外全都必定是1.
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
#define bug printf("*********\n");
#define debug(x) cout<<"["<<x<<"]" <<endl;
#define mid (l+r)/2
#define chl 2*k+1
#define chr 2*k+2
#define lson l,mid,chl
#define rson mid,r,chr
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a));
const long long mod=1e9+7;
const int maxn=5e5+5;
const int INF=0x7fffffff;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
int a[maxn];
int l,r;
int t,cas=1;
int Q;
char s[100];
deque<int> q;
int main() {
scanf("%d",&t);
while(t--) {
scanf("%d",&Q);
int x;
bool b=1;
l=r=2e5+5;
printf("Case #%d:\n",cas++);
q.clear();
while(Q--) {
scanf("%s",s);
if(b) {
if(s[0]=='P'&&s[1]=='U') {
scanf("%d",&x);
a[++r]=x;
if(x==0)q.push_back(r);
} else if(s[0]=='Q') {
if(r==l)printf("Invalid.\n");
else if(r-l==1)printf("%d\n",a[r]);
else {
if(q.size()==0) {
printf("%d\n",(r-l)&1);
} else {
int k=q.front();
if(r==k)printf("%d\n",(k-l+1)&1);
else printf("%d\n",(k-l)&1);
}
}
} else if(s[0]=='R') {
b=0;
} else {
if(a[r]==0)q.pop_back();
--r;
}
} else {
if(s[0]=='P'&&s[1]=='U') {
scanf("%d",&x);
a[l--]=x;
if(x==0)q.push_front(l+1);
} else if(s[0]=='Q') {
if(r==l)printf("Invalid.\n");
else if(r-l==1)printf("%d\n",a[r]);
else {
if(q.size()==0)printf("%d\n",(r-l)&1);
else {
int k=q.back();
if(k==l+1)printf("%d\n",(r-k)&1);
else printf("%d\n",(r-k+1)&1);
}
}
} else if(s[0]=='R') {
b=1;
} else {
if(a[l+1]==0)q.pop_front();
++l;
}
}
}
}
return 0;
}
I -題目連結:HDU - 5930 GCD
這題是真的難理解.這題要是不用線段樹大家都會寫吧,首先暴力從前面的每個位置到當前位置的GCD ,然後記錄每個GCD的個數,更新一個點就是刪除一個點,然後再加一個點,就是暴力從前面所有位置到後面所有位置的GCD,減去這個值。把值更新再一次算從前面所有位置到後面所有位置的GCD,然後加上去。
竟然會這個這個,這題就是用線段樹維護一下GCD的值,,,就像二分一樣,因為會有很長一段的GCD值是一樣的,每次不用一個個去找,直接找到前面GCD改變的位置,然後減去上一次GCD改變的位置。也是一種暴力。。。修改其實也是一樣的就是把前面GCD和後面GCD求一個GCD,然後前後GCD 的數量相乘
比如 1 1 1 2 4 4 4 前面3個數的GCD是3 個 1 和後面3個數 是 2 那麼GCD為 gcd(1,2) 數量就是 3 * 3;
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
#define bug printf("*********\n");
#define debug(x) cout<<"["<<x<<"]" <<endl;
#define mid (l+r)/2
#define chl 2*k+1
#define chr 2*k+2
#define lson l,mid,chl
#define rson mid,r,chr
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a));
const long long mod=1e9+7;
const int maxn=5e5+5;
const int INF=0x7fffffff;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
int g[maxn<<4],c[maxn];
int f[maxn<<4],a[maxn],aa[maxn],b[maxn],bb[maxn];
int A,B,n,m;
long long gcd(long long a,long long b) {
return b==0?a:gcd(b,a%b);
}
void build(int l,int r,int k) {
if(r-l==1) {
g[k]=c[r];
} else {
build(lson);
build(rson);
g[k]=gcd(g[chl],g[chr]);
}
}
int findleft(int l,int r,int k,int u,int v) {
if(r<=u) {
if(gcd(g[k],v)==v)return 0;
if(l+1==r)return r;
int x=findleft(rson,u,v);
if(x)return x;
else return findleft(lson,u,v);
}
if(u>mid) {
int x=findleft(rson,u,v);
if(x)return x;
}
return findleft(lson,u,v);
}
void getleft(int x) {
A=0;
for(int i=c[x],j=x,k; j!=0; j=k) {
k=findleft(0,n,0,j,i);
a[A]=j-k;
aa[A++]=i;
if(k==0)return ;
i=gcd(c[k],i);
}
return ;
}
int findright(int l,int r,int k,int u,int v) { //這個是用線段樹往左找GCD
if(l+1>=u) {
if(gcd(g[k],v)==v)return n+1;
if(l+1==r)return r;
int x = findright(lson,u,v);
if(x<=n)return x;
else return findright(rson,u,v);
}
if(u<=mid) {
int x=findright(lson,u,v);
if(x<=n)return x;
}
return findright(rson,u,v);
}
void getright(int x) {
B=0;
for(int i= c[x],j=x,k; j<=n; j=k) { //這個是暴力X所有左邊的GCD
k=findright(0,n,0,j,i);
b[B]=k-j;
bb[B++]=i;
i=gcd(c[k],i);
}
return ;
}
void change(int l,int r,int k,int u,int v) {
if (l+1==r) {
g[k] = v;
return;
}
if (u<=mid) change(lson,u,v);
else change(rson,u,v);
g[k]=gcd(g[chl],g[chr]);
}
int main() {
int t,cas=1;
scanf("%d",&t);
while(t--) {
printf("Case #%d:\n",cas++);
scanf("%d%d",&n,&m);
for(int i=1; i<=n; ++i)scanf("%d",&c[i]);
build(0,n,0); //初始化線段樹
memset(f,0,sizeof(f));
int ans=0;
for(int i=1; i<=n; i++) {
getleft(i); //初始化只要找所有i左邊的GCD或者右邊也可以,但是隻能找一邊不然會重複。
for(int j=0; j<A; j++) {
if(!f[aa[j]])ans++;
f[aa[j]]+=a[j];
}
}
while(m--) {
int x,y;
scanf("%d%d",&x,&y);
getleft(x); //找到所有左邊的GCD
getright(x); //找到所有右邊的GCD
for(int j=0; j<A; j++) {//暴力所有左右兩邊GCD所有可能
for(int k=0; k<B; k++) {
int t=gcd(aa[j],bb[k]); //左右兩邊的GCD的GCD
f[t]-=1LL *a[j]*b[k]; // 暴力刪除
if(!f[t])ans--;
}
}
c[x]=y;
change(0,n,0,x,y);
getleft(x);
getright(x);
for(int j=0; j<A; j++) {
for(int k=0; k<B; k++) {
int t=gcd(aa[j],bb[k]);//暴力新增
if(!f[t])ans++;
f[t]+=1LL*a[j]*b[k];
}
}
printf("%d\n",ans); // 得出結論
}
}
return 0;
}
J 題目連結:HDU5931 - Mission Possible
暴力所有速度,推一下公式,發現要麼是用初始血量去掉不加血,要麼是加血等於掉血數量的時候是最優解。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<stack>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
#define bug printf("*********\n");
#define debug(x) cout<<"["<<x<<"]" <<endl;
#define mid (l+r)/2
#define chl 2*k+1
#define chr 2*k+2
#define lson l,mid,chl
#define rson mid,r,chr
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a));
const long long mod=1e9+7;
const int maxn=5e5+5;
const int INF=0x7fffffff;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
ll D,A,GA,GB,GC;
int main() {
int t,cas=1;
scanf("%d",&t);
while(t--) {
scanf("%lld%lld%lld%lld%lld",&D,&A,&GA,&GB,&GC);
ll v,r,h;
ll ans=1e18,temp;
for(v=1; v<=D; v++) {
double t=1.0*D/v;
temp=v*GB+A*GC+A*GA;
ans=min(ans,temp);
double tem2=t*A;
temp=v*GB+floor(t*A-eps+1)*GA;
// debug(temp-v*GB);
ans=min(ans,temp);
}
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}