- A
- B
- C
- D
- E
- F
- G
- H
- I
- J
A
生活大爆炸版石頭剪刀布
純模擬,保證AB之間能對應就行。
給出較樸素做法。
bool caiquan(int,int);
int main(void)
{
int n,x,y,ans1 = 0,ans2 = 0,stp;
cin >> n >> x >> y;
vector<int> a(x);
vector<int> b(y);
for(auto &i : a) cin >> i;
for(auto &i : b) cin >> i;
for(int i=0,j=0,t=0;t < n;t++)
{
ans1 += caiquan(a[i],b[j]);
ans2 += caiquan(b[j],a[i]);
++i,++j;
if(i == x) i = 0;
if(j == y) j = 0;
}
cout << ans1 << ' ' << ans2 << '\n';
}
bool caiquan(int a,int b)
{
bool ans = false;
if(a == 0)
{
if(b == 2 || b == 3) ans = true;
}
else if(a == 1)
{
if(b == 0 || b == 3) ans = true;
}
else if(a == 2)
{
if(b == 1 || b == 4) ans = true;
}
else if(a == 3)
{
if(b == 2 || b == 4) ans = true;
}
else
{
if(b == 0 || b == 1) ans = true;
}
return ans;
}
B
笨小猴
模擬,可以開map模擬,但是隻出現字元,開數字模擬也可,甚至更快。
void func()
{
string st;
cin >> st;
map<char,int> cnt;
for(auto &i : st) cnt[i]++;
int mx = 0, mn = 0x3f3f;
for(auto &i : cnt)
{
mx = max(mx,i.second);
mn = min(mn,i.second);
}
if(slove(mx - mn)) cout << "Lucky Word\n" << mx - mn << '\n';
else cout << "No Answer\n0";
}
bool slove(int z)// 判素數
{
if(z <= 1) return false;
for(int i=2;i<=z/i;++i)
{
if(z % i == 0) return false;
}
return true;
}
C
過河卒
超綱題,二維dp。
根據題意,卒只能王下或者往右移動,所以$[i,j]$狀態由$[i-1,j]$和$[i,j-1]$轉移。
設$dp[i][j]$為移動到$(i,j)$的次數,那麼可得轉移方程:
$dp[i][j] = dp[i-1][j] + dp[i][j-1]$
但是因為馬的存在,有部分點不可移動,這時只需要單獨處理,到此處時$dp[i][j] = 0$即可。
因為想著最後一組題,特意出了點超綱的考演算法的題目。其實可能也不超綱,你們專業課好像學了動態規劃。
void func()
{
int n,m,a,b;
cin >> n >> m >> a >> b;
int dp[N][N];
int vis[N][N];
n += 2,m += 2,a += 2,b += 2;// 保證邊界往外一格存在,防RE
memset(vis,0,sizeof vis);
memset(dp,0,sizeof dp);
int dx[] = {1,2,2,1,-1,-2,-2,-1};
int dy[] = {2,1,-1,-2,-2,-1,1,2};// 表示馬的移動
dp[1][2] = 1;
vis[a][b] = 1;
for(int i=0;i<8;++i) vis[a+dx[i]][b+dy[i]] = 1;// 計算馬禁止的座標
for(int i=2;i<=n;++i)
{
for(int j=2;j<=m;++j)
{
dp[i][j] = dp[i-1][j] + dp[i][j-1];
if(vis[i][j] == 1) dp[i][j] = 0;
}
}
cout << dp[n][m] << '\n';
}
D
Contest Proposal
因為資料很小,可以寫暴力一點。
每次比較$a_i,b_i$,$a_i$不符合條件刪去,然後把$b_i$放入,再給$a$排序。這樣就能保證順序了。這時複雜度$O(n^2logn)$。
void func()
{
int n,ans = 0;
cin >> n;
vector<int> a(n),b(n);
for(auto &i : a) cin >> i;
for(auto &i : b) cin >> i;
for(int i=0;i<n;++i)
{
if(b[i] < a[i])
{
a.pop_back();
a.push_back(b[i]);
sort(a.begin(),a.end());
ans ++;
}
}
cout << ans << '\n';
}
實際可以用更短的程式碼寫出$O(n)$的解法。
因為在$a_i > b_i$後插入了新數字,這個數字大小一定在$a_{i-1}$和$a_i$之間,所以和$b_{i+1}$比較的還是$a_i$。具體如下。
void func()
{
int n,ans = 0;
cin >> n;
vector<int> a(n),b(n);
for(auto &i : a) cin >> i;
for(auto &i : b) cin >> i;
for(int i=0,j=0;j<n;++j)
{
if(a[i] <= b[j]) ++i;
else ans++;
}
cout << ans << '\n';
}
E
Coin Games
每個人操作實際只有以下三種情況。
分別使實際可操作次數$+2,-2,$不變。在邊界操作不翻轉,可理解成第三種情況。每次操作都使得可操作次數$-1$後偶數次變化,都不影響結果。因為答案就是可操作次數的奇偶性。
void func()
{
int n;
string st;
cin >> n >> st;
int cnt = 0;
for(int i=0;i<n;++i)
if(st[i] == 'U') cnt++;
if(cnt % 2) cout << "YES\n";
else cout << "NO\n";
}
F
Phone Desktop
每個螢幕$3 \times 5$,可放$2$個$2 \times 2$,其餘可填$7$個$1 \times 1$先算$2 \times 2$需要多少個螢幕,再算當前螢幕是否可放下所有$1 \times 1$,根據$1 \times 1$的量加螢幕。
void func()
{
int a,b;
cin >> a >> b;
int ans = (b+1) / 2;
int stp = a - (ans*15 - 4*b);
if(stp > 0) ans += (stp + 14) / 15;
//當前螢幕是否可以放下所有a,不能則再加螢幕.
cout << ans << '\n';
}
G
Chess For Three
因為每次對弈都使總分$+2$,所以總分不是偶數則不可能。
又因為求最大可能和棋次數。那麼先考慮全和棋的情況。
全和棋和棋數為得分$/2$,因為$c$得分最高,所以參與了最多次的對弈。
考慮極限情況,所有對弈都有$c$參與。可得:
- 在$a + b = c$ 時,$a,b$可以全向$c$和棋。答案即為總分$/2$。
進而可推得:
- 在$a + b < c$ 時,全和棋不滿足答案,$a,b$全向$c$和棋,$c$再贏若干次。和棋次最多。答案即$(a+b) / 2$
- 在$a + b > c$ 時,全和棋是滿足答案的。答案即為總分$/2$。
void func()
{
int a,b,c;
cin >> a >> b >> c;
int sum = 0;
sum = a + b + c;
if(sum % 2 == 0) cout << (a + b >= c ? sum / 2 : a + b) << '\n';
else cout << -1 << '\n';
}
H
Symmetric Encoding
按題意處理出$r$串,使得對稱對映就行。
void func()
{
int n;
string st,r;
cin >> n >> st;
r = st;
sort(r.begin(),r.end());
r.erase(unique(r.begin(),r.end()),r.end());
int len = r.size();
map<char,char> mp;
for(int i=0;i<len;++i) mp[r[i]] = r[len - 1 - i];
for(int i=0;i<n;++i) st[i] = mp[st[i]];
cout << st << '\n';
}
I
Little Nikita
設放上的操作有$x$次,拿下的操作有$y$次,那麼可得
- $x = y = n $
- $x - y = m $
那麼$n + m = 2 \times x$,$n + m$為偶數。
void func()
{
int n,m;
cin >> n >> m;
if((n + m) % 2 == 0 && n >= m) cout << "YES\n";
else cout << "NO\n";
}
J
Update Queries
題意說明:可以將$s$按$ind$陣列的索引替換為$b$中對應字元。對$ind$和$b$排序,使得結果字串的字典序最小。
因為並不需要輸出排列後的$ind$和$b$,所以只需要輸出最小字典序的答案即可,二者排序並不重要。
只需要將$ind$代表的可替換位置,從前到後替換為$b$中從小到大的字元。
void func()
{
int n,m;
cin >> n >> m;
string s,c;
cin >> s;
set<int> ind;
while(m--)
{
int stp;cin >> stp;
ind.insert(stp);
}
cin >> c;
sort(c.begin(),c.end());
int j=0;
for(auto &i : ind) s[i-1] = c[j++];
cout << s << '\n';
}