10.26 考試總結
\(T2\) 原本能過的,結果特判了 \(k=1\) 的情況,就 \(tm\) 哪裡全錯了。就 \(nm\) 離譜
$ T3$ 打的暴力也不知道哪裡打掛了。
T1 Diy 手工
desprition
H 小姐的生日很快就要到了,小 Z 還在思索應該送 H 小姐什麼生日禮物 才好。送化妝品太貴,送巧克力又太俗
了……突然,小 Z 靈機一動,打算做一 個 diy 手工以顯誠意。 小 Z 找來了好多長度為 N 的冰棒棍,他打算把
這些冰棒棍切割成若干段,然後拼接成一個個長方體,然後再用這些長方體壘成城堡。然而,小 Z 卻開始 為長方
體長寬高的選取而煩惱:設長方體的長寬高分別為 \(L,W,H\),為了更好地 利用這些長度為 \(N\)
小 Z 希望把這些冰棒棍分為四組,其中第一組都 能恰好切割成若干段長(L 整除 N),
第二組切割成若干段寬(W 整除 N),第三 組切割成若干段高(H 整除 N),
最後一組恰好切割成長寬高各(N=L+W+H)。 現在,小 Z 好奇,拼成的長方體,體積最大是多少?
output
每組測試資料輸出一行,包含一個整數,表示長方體的最大體積。若不 存在合法方案,輸出 \(-1\)。
對於 100% 的資料範圍 \(T\leq 10^6,n\leq 10^6\)
solution
打表找規律題。
結論:
-
當 \(n \bmod 3 == 0\) 答案為 \(({n\over 3})^3\)
-
除此之外當 \(n\bmod 4 == 0\) 答案為 \({n\over2} \times {n\over 4}\times{n\over 4}\)
-
否則無解
Code
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int T,n; inline int read() { int s = 0,w = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();} return s * w; } int main() { freopen("diy.in","r",stdin); freopen("diy.out","w",stdout); T = read(); while(T--) { n = read(); if(n % 3 == 0) printf("%lld\n",1LL * (n/3) * (n/3) * (n/3)); else if(n % 4 == 0) printf("%lld\n",1LL * (n/2) * (n/4) * (n/4)); else printf("%d\n",-1); } fclose(stdin); fclose(stdout); return 0; }
T2 tower
Desprition
勇 士 有 \(K\) 個 屬 性 , 大 小 分 別 為 \(v[1],v[2],…,v[K]\),一共有 \(N\) 只怪物,每隻怪物也有相應的 \(K\) 個屬性,
第 \(i\) 只 怪 物 的 第 \(j\) 項 屬 性 標 記 為 \(a[i][j]\) 。 若 對 於 任 意 的 \(j\) ( \(1≤j≤K\) ) 都 有 \(a[i][j]≤v[j]\),
則勇士可以幹掉第 \(i\) 只怪物,而且幹掉第 \(i\) 只怪物後,勇士的 各項屬性都會得到提升,
其中第 \(j\) 項屬性的提升了 \(b[i][j]\)。 現在小 Z 好奇,按照最優策略來打怪,最多能幹掉多少隻怪物。
input
第一行為測試資料組數 \(T(1≤T≤10)\)。 每組測試資料的第一行為怪物數 \(N\) 及屬性數 \(K\) 。
第二行包含 \(K\) 個非負整數分別表示 \(v[1],v[2],…,v[K]\)。
接下來 \(N\) 行,第 \(i\) 行包含$ 2\times K$ 個非負整數,表示 \(a[i][1],a[i][2],…a[i][K]\) 和 \(b[i][1],b[i][2],…,b[i][K]\)。
具體含義見題面。
output
對於每組測試資料,輸出第一行包含一個整數 \(M\),表示小 Z 最多能幹掉多 少只怪物。
第二行包含 \(K\) 個整數,表示幹掉 \(M\) 只怪物後,勇士的 \(K\) 項屬性分別 是多少
solution
暴力跑的比正解還快,加個快讀就過了 。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5+10;
int T,n,k,maxn,ans;
int t[N],a[N][6],b[N][6];
bool vis[N];
struct node
{
int id,w;
}e[N];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
bool comp(node a,node b)
{
return a.w < b.w;
}
bool judge(int x)
{
for(int i = 1; i <= k; i++)
{
if(t[i] < a[x][i]) return 0;
}
return 1;
}
int main()
{
freopen("tower.in","r",stdin);
freopen("tower.out","w",stdout);
T = read();
while(T--)
{
n = read(); k = read(); ans = 0;
memset(vis,0,sizeof(vis));
for(int i = 1; i <= k; i++) t[i] = read();
for(int i = 1; i <= n; i++)
{
int sum = 0;
for(int j = 1; j <= k; j++)
{
a[i][j] = read();
sum += max(0,a[i][j] - t[j]);
}
for(int j = 1; j <= k; j++) b[i][j] = read();
e[i].id = i; e[i].w = sum;
}
sort(e+1,e+n+1,comp);
while(1)
{
int num = 0;
for(int i = 1; i <= n; i++)
{
if(vis[i]) continue;
else if(judge(e[i].id))
{
num++; vis[i] = 1;
for(int j = 1; j <= k; j++) t[j] += b[e[i].id][j];
}
}
if(num == 0) break;
ans += num;
}
printf("%d\n",ans);
for(int i = 1; i <= k; i++) printf("%d ",t[i]);
printf("\n");
}
fclose(stdin); fclose(stdout);
return 0;
}
T3 sport
Desprition
一年一度的趣味運動會馬上就要開始啦!作為班長的小 Z 最近正忙於制定 策略,決定派哪些同學參加哪些
趣味專案。其中最棘手的莫過於二人三足,顧 名思義,這個運動需要每組兩位同學默契配合,才能走得儘可
能的快。 已知全班共有 \(N\) 位同學報名參加趣味運動會,小 Z 需要在這 \(N\) 位同學中選 出若干對同學,
組隊參加二人三足。可惜的是,這 \(N\) 位同學之間總是小摩擦不 斷,說不準昨天 \(A\) 和 \(B\) 吵架了,
不再適合組隊,而沒過多久,前天吵架的 \(C\) 和 \(D\) 就又突然和好了。
小 Z 得知這 \(N\) 位同學的吵架及和好事件的發生,他好奇每 發生一次吵架或和好後,
派出 \(k\) 組同學參加二人三足的方案數,分別是多少。
其中 \(k=1,2,……,N/2\)。
input
第一行為測試資料組數 \(T(1≤T≤10)\)。 每組測試資料的第一行為學生數量 \(N\) 及事件數 \(M\) .
其中 \(N\) 為偶數。 接下來 \(M\) 行,第 \(i\) 行通過一個三元組 \(c u v\) 描述一個事件,
其中 \(c\) 為字元, 要麼是“+”要麼是“-”,
而 \(u\) 和$ v$ 為吵架(用“-”表示)或和好(用“+”表 示)的兩位同學的編號。
資料保證兩位剛和好的同學之前處於吵架狀態,而剛吵架的同學之前處於 和好狀態。
output
每組資料輸出 \(M\) 行,包含 \(N/2\) 個數字,第 \(k\) 個數字表示派出 \(k\) 組同學參賽 的方案數對 \(10^9+7\) 取模後是多少。
\(T\leq 10,n\leq 10,m\leq 3000\)
sloution
狀壓 \(dp\) .
設 \(f[i][j]\) 表示選的人的集合為 \(i\) ,配對數為 \(j\) 的方案數。
初始化 : \(f[0][0] = 1\)
轉移時列舉每個不選 \(u,v\) 的狀態 \(i\) 進行轉移。
設 \(tmp = (1<<(u-1)) | (1<<(v-1))\)
若 \(u,v\) 和好,則 \(f[i\) $or $ $ tmp] $ \([j] += f[i][j-1]\) \(ans[j] += f[i][j-1]\) .
反之 \(f[i\) \(or\) $ tmp][j] -= f[i][j-1]$ \(ans[j] -= f[i][j-1]\)
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int p = 1e9+7;
int T,n,m,u,v,f[100010][6],ans[6];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
int main()
{
freopen("sport.in","r",stdin);
freopen("sport.out","w",stdout);
T = read();
while(T--)
{
memset(f,0,sizeof(f));
memset(ans,0,sizeof(ans));
n = read(); m = read();
f[0][0] = 1;
for(int Q = 1; Q <= m; Q++)
{
char ch = getchar();
while(ch != '+' && ch != '-') ch = getchar();
u = read(); v = read();
if(ch == '+')
{
int k = ((1<<n)-1) ^((1<<(u-1)) | (1<<(v-1)));
int tmp = ((1<<(u-1)) | (1<<(v-1)));
for(int i = k; ; i = (i-1) & k)//列舉每個不選 u,v的狀態進行轉移
{
for(int j = 1; j <= n/2; j++)
{
f[i | tmp][j] = (f[i | tmp][j] + f[i][j-1]) % p;
ans[j] = (ans[j] + f[i][j-1]) % p;
}
if(!i) break;
}
}
else
{
int k = ((1<<n)-1) ^ ((1<<(u-1)) | (1<<(v-1)));
int tmp = ((1<<(u-1)) | (1<<(v-1)));
for(int i = k; ; i = (i-1) & k)
{
for(int j = 1; j <= n/2; j++)
{
f[i | tmp][j] = (f[i | tmp][j] - f[i][j-1] + p) % p;
ans[j] = (ans[j] - f[i][j-1] + p) % p;
}
if(!i) break;
}
}
for(int i = 1; i <= n/2; i++) printf("%d ",ans[i]);
printf("\n");
}
}
fclose(stdin); fclose(stdout);
return 0;
}