2018 Multi-University Training Contest 6
Werewolf
只考慮村民邊,然後每個村民邊求聯通塊,最後加狼邊,看看兩個端點在不在一個聯通塊裏就可以了。 比賽的時候有點坑,思路正確,寫歪了……
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 50;
vector<int> g[maxn];
int fa[maxn];
int in[maxn];
int lang[maxn];
int cnt[maxn];
void dfs(int u, int root) ///同屬一個根
{
fa[u] = root;
for(int i = 0; i < g[u].size(); i++)
{
dfs(g[u][i], root);
cnt[u] += cnt[g[u][i]];
}
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++) g[i].clear(), fa[i] = 0, in[i] = 0, cnt[i] = 1, lang[i] = 0 ;
for(int i = 1; i <= n; i++)
{
int v;
char s[15];
scanf("%d %s", &v, s);
if(s[0] == ‘v‘)
{
g[v].push_back(i);
in[i]++;
}
else lang[i] = v;
}
for(int i = 1; i <= n; i++) if(!in[i]) dfs(i, i);
int ans = 0;
for(int i = 1; i <= n; i++)
{
if(!in[i] && (fa[lang[i]] == i)) ans += cnt[lang[i]];
}
printf("0 %d\n", ans);
}
return 0;
}
/*423
6
2 v
3 v
4 v
5 v
3 w
4 v
*/
Code
bookshelf
這題首先要找到規律:
$gcd(2^{a}-1,2^{b}-1)=2^{gcd(a,b)}-1.$
這個看大家都沒有證明,我看了dls的講解後,還有問學長,給出下面證明:
設$a < b;$
$gcd(2^{a}-1,2^{b}-1)$
$=gcd(2^{a}-1-(2^{b}-1)\times 2^{a-b},2^{b}-1)$ (這個和正常的輾轉相除一樣:$gcd(a,b)=gcd(a-b\times \lfloor a / b\rfloor , b)$)
整理得:
$=gcd(2^{a-b}-1,2^{b}-1)$
繼續:
$=gcd(2^{a-2\times b}-1,2^{b}-1)$
……
$=gcd(2^{a\%b}-1,2^{b}-1)$
然後這時候$a\%b < b$,再像正常的那樣反過來繼續$gcd$就行,直到一邊$a\%b=0,2^{0}-1=0,$那麽最後的$gcd$就是$2^{g}-1$,而$g=gcd(a,b)$,證明完畢。
而$gcd(fib(a),fib(b))=fib(gcd(a,b))$,這位老鐵給出了證明。
而最後化簡完求的是:$2^{gcd(f[x1],f[x2],……,f[xk])}=2^{f[gcd(x1,x2,……,xk)]}。$
令$d=gcd(x1,x2,……,xk),$相當於$d|x1,d|x2,……,d|xk.$
對$x1,x2,……,xk$求和,得$\frac{x1+x2+……+xk=n}{d}.$ 問題演化為:有k個數,每個數都可以除以d,並且k個數的和是n,問這樣的數的組合有多少種?
利用隔板法:可以先把n分成n/d份,然後得出組合數$C(n/d+k-1,k-1)$。
這時,我們令f[d]表示 $d | gcd(x1,x2,……,xk)$的方案數。
令g[d]表示$d=gcd(x1,x2,……,xk)$的方案數。
則$f[d]=C(n/d+k-1,k-1)$。
而$g[d]=f[d]-\sum_{d|x} g[x]$,從大到小枚舉因子就可以了。
不太懂f[d]和g[d]的關系,我們可以舉個例子,假如$n=12,k=3,$首先枚舉d=1,那麽f[d]不僅包括$gcd=1$的,還包括$gcd=2、3、4、6、12$的,所以我們只算$gcd=1$的,減去其他的就可以了,最後答案再乘以$2^{fib[d]}-1$就可以了。
因為指數特別大,最後再利用歐拉降冪公式 不要求a和n互質。
這裏n是質數,$a^{\varphi(n)} \% n=1$,根據費馬小定理,所以可以不用加後面。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e6 + 50; typedef long long ll; int fac[maxn]; int sing[maxn]; int inv[maxn]; int f[maxn / 2]; int g[maxn / 2]; int fib[maxn / 2]; const ll mod = 1e9 + 7; void init(int n) { fac[0] = fac[1] = sing[0] = sing[1] = inv[0] = inv[1] = 1; for(int i = 2; i <= n; i++) { fac[i] = (ll)fac[i - 1] * i % mod; sing[i] = (ll)(mod - mod / i) * sing[mod % i] % mod; inv[i] = (ll)inv[i - 1] * sing[i] % mod; } } ll quick_pow(ll a,ll n) { ll res = 1; while(n) { if(n % 2LL) res = res * a % mod; n >>= 1LL; a = a * a % mod; } return res; } vector<int> yue; int main() { duipai(); init(2e6 + 10); int T; scanf("%d", &T); fib[0] = 0, fib[1] = fib[2] = 1; ll fain = mod - 1; int early = maxn; for(int i = 3; i <= (1e6 + 5); i++) { fib[i] = fib[i - 1] + fib[i - 2]; if((ll)fib[i] > fain) { if(maxn == early) early = i; fib[i] = (ll)fib[i] % fain; } } while(T--) { yue.clear(); int n, k; scanf("%d %d", &n, &k); for(int i = 1; i <= n; i++) { f[i] = 0; g[i] = 0; if(n % i == 0) { yue.push_back(i); f[i] = (ll)fac[n / i + k - 1] * inv[k - 1] % mod * (ll)inv[n / i] % mod; } } ll ans = 0; for(int i = yue.size() - 1; i >= 0; i--) { int d = yue[i]; g[d] = f[d]; for(int j = i + 1; j < yue.size(); j++) { int x = yue[j]; if(x % d == 0) g[d] = ((ll)g[d] + mod - (ll)g[x]) % mod; } } for(int i = 0; i < yue.size(); i++) { int d = yue[i]; ll mi = fib[d] + (d >= early ? fain : 0); ans = (ans + (ll)g[d] * ((quick_pow(2LL, mi) - 1LL + mod) % mod) % mod) % mod; } ans = (ans * quick_pow((ll)f[1], mod - 2)) % mod; printf("%lld\n", ans); } return 0; }Code
sacul
Shoot Game
Ringland
Variance-MST
2018 Multi-University Training Contest 6