1. 程式人生 > >codeforces round #428 div2

codeforces round #428 div2

double span ide line ++i getch 表示 isp name

A:暴力模擬,能加就加,如果累計到了8就加上,每次累積

技術分享
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,k ,cnt = 0;
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i)
    {
        int x;
        scanf("%d", &x);
        cnt += x;
        if(cnt >= 8) 
        {
            k 
-= 8; cnt -= 8; } else { k -= cnt; cnt = 0; } if(k <= 0) { printf("%d\n", i); return 0; } } puts("-1"); return 0; }
View Code

B:模擬,情況有點多,先每四個人分配位置,四人座不夠分配二人座,然後每兩個人分配,兩人坐沒了分配四人座,分配四人座的時候每次統計+1,如果兩人四人都沒了兩個四人座剩下的可以給兩個人坐在邊上,剩下一個人就把兩人坐四人座分配,兩人座可以做一個人,四人座可以做兩個人,之前統計+1可以坐一個人

技術分享
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, k;
int a[N];
int main()
{
    scanf("%d%d", &n, &k);
    int cnt1 = n * 2, cnt2 = n, one = 0; 
    for(int i = 1; i <= k; ++i) 
    {
        scanf("%d", &a[i]);
        int x = a[i] / 4;
        a[i] %= 4;
        
if(cnt2 >= x) cnt2 -= x; else { x -= cnt2; cnt2 = 0; if(cnt1 >= 2 * x) cnt1 -= 2 * x; else { puts("NO"); return 0; } } } for(int i = 1; i <= k; ++i) { if(a[i] == 0) continue; int x = a[i] / 2; a[i] %= 2; if(cnt1 >= x) cnt1 -= x; else { x -= cnt1; cnt1 = 0; if(cnt2 >= x) { cnt2 -= x; one += x; } else if(one >= x * 2) { one -= x * 2; } else { puts("NO"); return 0; } } } one += 2 * cnt2 + cnt1; for(int i = 1; i <= k; ++i) { if(a[i] == 0) continue; --one; if(one < 0) { puts("NO"); return 0; } } puts("YES"); return 0; }
View Code

C:一個比較簡單的概率dp,每次dp[v]=dp[u]/(size[u]-(last == 0)),如果是根節點last=0沒有前繼,概率就是度數,否則度數-1,然後葉子結點的概率乘上步長就是答案

技術分享
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
double ans;
double dp[N];
vector<int> G[N];
void dfs(int u, int last, int dis)
{
    if(G[u].size() == 1) ans += dp[u] * (double)dis; 
    for(int i = 0; i < G[u].size(); ++i)
    {
        int v = G[u][i];
        if(v == last) continue;
        dp[v] = dp[u] * 1.0 / (double)(G[u].size() - (last != 0));
        dfs(v, u, dis + 1);
    }
}
int main()
{
    scanf("%d", &n);
    dp[1] = 1.0;
    for(int i = 1; i < n; ++i)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, 0, 0);
//    for(int i = 1; i <= n; ++i) printf("dp[%d]=%.6f\n", i, dp[i]);
    printf("%.8f\n", ans);
    return 0;
}
View Code

D:一個很好的題,我們用容斥原理來做,設cnt[i]表示能整除i的a[i]的個數,ans[i]表示gcd為i的子序列的答案,我們發現直接計算ans似乎有些困難,但是我們可以容斥,我們放寬條件,先找出gcd能整除i的子序列的人的總和的可能的總數,是C(n,1)*1+C(n,2)*2+C(n,3)*3+...+C(n,n)*n,意思是n個人選1個人的方案數*1個人,n個人選兩個人*兩個人,統計了所有子序列的總人數,然後我們加一項C(n,0)*0,然後倒序相加,就得到了n*(C(n,0)+C(n,1)+...+C(n,n))/2=n*2^n/2=n*2^n-1,這是gcd是n的倍數的答案,然後根據容斥原理,我們把ans[i*2],ans[i*3]...減去,剩下的就是答案

這其實跟莫比烏斯反演挺像的,就是限制太強就用容斥弱化一下

技術分享
#include<bits/stdc++.h>
using namespace std;
const int N = 200010, mod = 1000000007; 
int n;
int a[N], has[N * 10], cnt[N * 10];
long long ans[N * 10];
long long answer;
inline int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < 0 || c > 9) { if(c == -) f = -1; c = getchar(); }
    while(c >= 0 && c <= 9) { x = x * 10 + c - 0; c = getchar(); }
    return x * f;
}
long long power(long long x, long long t)
{
    long long ret = 1;
    for(; t; t >>= 1, x = x * x % mod) if(t & 1) ret = ret * x % mod;
    return ret;
}
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) 
    {
        a[i] = read();
        ++has[a[i]];
    }
    for(int i = 2; i <= 1000000; ++i)
        for(int j = i; j <= 1000000; j += i) cnt[i] += has[j];
    for(int i = 1000000; i >= 2; --i) if(cnt[i] > 0)
    {
        ans[i] = (long long)cnt[i] * (long long)power(2, cnt[i] - 1) % mod;
        for(int j = i * 2; j <= 1000000; j += i) ans[i] -= ans[j];
        answer = (answer + (long long)i * ans[i]) % mod;
    }
    printf("%lld\n", (answer % mod + mod) % mod);
    return 0;
}
View Code

codeforces round #428 div2