1. 程式人生 > 實用技巧 >Codeforces Round #652 (Div. 2) 總結

Codeforces Round #652 (Div. 2) 總結

A:問正n邊形的一條邊和x軸平行的時候有沒有一條邊和y軸重合,直接判斷n是否是4的倍數

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std; typedef long long ll;
typedef pair<int,int> pi; int main() {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d", &n);
if (n % == ) puts("YES");
else puts("NO");
}
}

B題:給一個01串每次可以從連續的“10”中刪去0或1(不能同時刪去),問可以得到的最小字典序字串。

字串中開頭的0是去不掉的,末尾的1是去不掉的。中間是1開頭的01串,可以發現這堆東西能變成一個"0"。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std; typedef long long ll;
typedef pair<int,int> pi;
const int N = 1e5 + ; char s[N];
int top;
int n;
char a[N];
void solve() {
scanf("%d", &n);
memset(a, , sizeof (a));
memset(s, , sizeof (s));
top = ;
scanf("%s", a + );
int f = ;
rep(i,,n) {
if (!f && a[i] == '') {
putchar(a[i]);
continue;
}
if (a[i] == '') f = , s[++top] = a[i];
if (a[i] == '') top = , s[] = '';
}
rep(i,,top) putchar(s[i]);
puts("");
} int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
}

C題:給你n個數字,分給k個小夥伴,每個人分得w_i個數字,小夥伴的快樂值是他得到的數字中的最大值加最小值。求所有小夥伴快樂值的和最大是多少。

首先把小夥伴按分得數字個數從小到大排序,數字按從大到小排序。先把最大的k個按這樣的順序分給大家每人一個,然後剩下的數字從第一個小夥伴開始給,到這個小夥伴拿夠,給下一個人。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std; typedef long long ll;
typedef pair<int,int> pi;
const int N = 2e5 + ;
int w[N], a[N], n, k; void solve() {
scanf("%d %d", &n, &k);
ll ans = ;
rep(i,,n) scanf("%d", &a[i]);
rep(i,,k) scanf("%d", &w[i]);
sort(a + , a + n + );
sort(w + , w + k + );
reverse(a + , a + n + );
rep(i,,k) ans += a[i];
int cnt = k;
rep(i,,k) {
if (w[i] >= ) {
if (w[i] == ) ans += a[i];
else {
while (w[i] != ) {
cnt++;
w[i]--;
}
ans += a[cnt];
}
}
}
printf("%lld\n", ans);
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
solve();
}
}

D:有一個叫RDB的有根樹。一階RDB只有根結點。i階RDB是在i-1階的RDB上發生一些變化:對於沒有兒子的節點,長出一個兒子;有一個兒子的節點,再長兩個兒子,其餘節點不發生變化。欽定一個點和他的三個兒子叫做爪子。然後問你在n階段RDB上最多能找到多少個不重疊的爪子。

問題在有三個兒子的結點什麼時候會被選什麼時候不會被選。當這個結點第一次有三個兒子的時候,選這個結點,一定不比選他的父親那個結點差,這個時候必選這個結點。更高一階他中間的兒子結點將有三個兒子,更高兩階他的左右兩個兒子會有三個兒子,這時候顯然不選這個結點。而更高3階的時候就會選這個結點。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std; typedef long long ll;
typedef pair<int,int> pi;
const int N = 2e6 + ;
const int mod = 1e9 + ;
ll f[N][]; void init(){
f[][] = ;
rep(i,,) {
f[i][] = f[i-][];
f[i][] = f[i-][];
f[i][] = (f[i-][] + f[i-][]) % mod;
//temp = f[2];
f[i][] = f[i-][];
f[i][] = (f[i-][] + * f[i-][]) % mod;
}
} void solve() {
int n;
scanf("%d", &n);
printf("%lld\n",f[n][] * % mod);
} int main() {
init();
int t;
scanf("%d", &t);
while (t--) {
solve();
}
}

E:你有一些朋友,每個人有兩道愛吃的菜x_i, y_i。然後每道菜有w_i份。當一個朋友來的時候會吃ta喜歡的菜,如果有兩道就吃兩道,有一道就吃一道,如果沒有就會吃了你。請問你應該怎麼安排朋友吃菜的順序,來讓大家都吃到至少一道自己喜歡吃的菜,或者無論怎麼安排都會有人吃不到。

設喜歡吃某道菜的人數為s_i,如果所有的s_i 都小於 w_i那麼就無解,顯然最後一個人的菜一定都被別人吃光了。對於wi >= si的菜,這些人多會吃都有關係。所以我們放在後面,這樣他們就會吃的少一點。然後按照這種方法一直做就好了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std; typedef long long ll;
typedef pair<int,int> pi;
const int N = 2e5 + ;
const int mod = 1e9 + ; int n, m;
vector<int> d[N];
int s[N], w[N], a[N], b[N], vis[N];
int ans[N], cnt = ;
int main() {
scanf("%d%d", &n, &m);
rep(i,,n) scanf("%d", &w[i]);
rep(i,,m) {
scanf("%d %d", &a[i], &b[i]);
s[a[i]]++;
s[b[i]]++;
d[a[i]].push_back(i);
d[b[i]].push_back(i);
}
queue<int> q;
rep(i,,n) if (s[i] <= w[i]) q.push(i);
while (!q.empty()) {
int j = q.front(); q.pop();
int _ = (int)d[j].size();
rep(i,,_-) {
if (!vis[d[j][i]]) {
int u = a[d[j][i]], v = b[d[j][i]];
if (u == j) swap(u, v);
s[u]--;
if (s[u] == w[u]) q.push(u);
vis[d[j][i]] = ;
ans[++cnt] = d[j][i];
}
}
}
if (cnt < m) {
puts("DEAD");
return ;
}
puts("ALIVE");
reverse(ans + , ans + cnt + );
rep(i,,cnt) printf("%d ", ans[i]); puts("");
}

f題:有一個遊戲,有兩個數s,e每次可以把s變成s + 1或者是s * 2,當s大於e時,就輸了。有n輪遊戲,每輪遊戲輸的人先手開始下一輪遊戲。在最後一輪贏了的人,贏得了遊戲。在最後一輪輸的人,輸掉了遊戲。

問先手能否必勝,同時先手能否一定失敗。

定義一下win(s,e)和lose(s,e)表示先手是否能一定贏和一定輸。

e是奇數的時候s奇數必敗s是偶數必勝。(可以自己寫一寫看一下)。e是偶數的時候,s大於e/2,s是奇數必勝,偶數必敗。s大於e/4的時候,無論s是什麼都能必勝。否則就是win(s, e/4)

對於先手強制輸的情況,如果s * 2 > e一定可以輸,否則等價於win(s, e / 2)

然後對於遊戲的輸贏就是,就是從最後局開始遞迴,如果這局能先手必勝(敗),上一局就必須要輸,否則上一局就必須要贏。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#define rep(i,j,k) for(int i = j; i <= k; i++)
#define dow(i,j,k) for(int i = j; i >= k; i--)
#define ez(i,x) for(int i = h[x]; i; i = e[i].next)
#define fi first
#define se second
using namespace std; typedef long long ll;
typedef pair<int,int> pi; const int N = 1e5 + ;
ll e[N], s[N];
bool w[N], l[N];
int n; bool Win(ll s, ll e) {
if ((e & )) {
if (s & ) return ;
return ;
}
if (s > e) return ;
if (s * > e) return (bool)(s & );
if (s * > e) return ;
return Win(s, e / );
} bool Lose(ll s, ll e) {
if (s * > e) return ;
return Win(s, e / );
} int getWin(int);
int getLose(int); int getWin(int x) {
if (x == ) return (int)w[];
return w[x]? getLose(x - ) : getWin(x - );
} int getLose(int x) {
if (x == ) return (int)l[];
return l[x]? getLose(x - ) : getWin(x - );
}
int main() {
//ios::sync_with_stdio(0);
scanf("%d", &n);
rep(i,,n) {
scanf("%lld %lld", &s[i], &e[i]);
w[i] = Win(s[i], e[i]);
l[i] = Lose(s[i], e[i]);
// cout << w[i] << " " << l[i] << endl;
}
printf("%d %d\n",getWin(n), getLose(n));