ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2020 ccpc online

2020-09-21 18:32:42  阅读:220  来源: 互联网

标签:cnt return int ll ans ccpc 2020 online SG


A

B 找下规律发现答案是[2,n]的和加上[2,n]的素数和, 直接min_25

C 队友过的

根据SG定理可以得到$SG(n)=\mathop{mex} \{SG(\frac{n}{d})\oplus ...\oplus SG(\frac{n}{d}) \} $, 异或$d$次, $d$是$n$的因子

只有$d$为奇数时有贡献, $SG(n)=\mathop{mex}\limits_{d|n,\text{$d$为奇}} \{ SG(\frac{n}{d}) \}$

找下规律就可以得到 $SG(pn)=SG(n)+1, p>2$

$n$为偶时, $SG(2n)=SG(n)$, $n$为奇时, $SG(2n)=SG(n)+1$

筛一下素因子即可

#include <bits/stdc++.h>
#define ctz __builtin_ctzll
typedef long long ll;
using namespace std;

mt19937 rd(time(0));
const int p[12]={2,3,5,7,11,13,17,19,23,29,31,37};
const int p_cnt=12;

ll mmul(ll a,ll b,ll m) { //a*b%m
    ll d=((long double)a/m*b+1e-8);
    ll r=a*b-d*m;
    return r<0?r+m:r;
}
ll FastPow(ll a,ll b,ll m) {
    ll ans=1;
    for (;b;b>>=1,a=mmul(a,a,m))
        if (b&1) ans=mmul(ans,a,m);
    return ans;
}
ll gcd(ll a,ll b) {
    if (!a||!b) return a+b;
    int t=ctz(a|b); a>>=ctz(a);
    do {
        b>>=ctz(b);
        if (a>b) swap(a,b);
        b-=a;
    } while (b);
    return a<<t;
}

int isprime(ll n) {
    if (n==1) return 0;
    if (n==2||n==3||n==5) return 1;
    if (!(n&1)||!(n%3)||!(n%5)) return 0;

    ll m=n-1; int k=0;
    while (!(m&1)) m>>=1,++k;
    for (int ip=0;ip<p_cnt&&p[ip]<n;++ip) {
        ll x=FastPow(p[ip],m,n),y=x;
        for (int i=0;i<k;++i) {
            x=mmul(x,x,n);
            if (x==1&&y!=1&&y!=n-1) return 0;
            y=x;
        }
        if (x!=1) return 0;
    }
    return 1;
}

ll f[110];
int cnt;

ll g(ll x,ll n,ll a) {
    ll t=mmul(x,x,n)+a;
    return t<n?t:t-n;
}

const int M=(1<<7)-1;
ll Pollard_Rho(ll n) {
    if (!(n&1)) return 2;
    if (!(n%3)) return 3;
    if (!(n%5)) return 5;

    ll x=0,y=x,t=1,q=1,a=(rd()%(n-1))+1;
    for (int k=2;;k<<=1,y=x,q=1) {
        for (int i=1;i<=k;++i) {
            x=g(x,n,a);
            q=mmul(q,abs(x-y),n);
            if (!(i&M)) {
                t=gcd(q,n);
                if (t>1) break;
            }
        }
        if (t>1||(t=gcd(q,n))>1) break;
    }
    if (t==n) {
        t=1;
        while (t==1) t=gcd(abs((x=g(x,n,a))-y),n);
    }
    return t;
}

void work(ll n) {
    if (n==1) return;
    if (isprime(n)) f[++cnt]=n;
    else {
        ll t=n;
        while (t==n) t=Pollard_Rho(n);
        work(t),work(n/t);
    }
}


const int N = 1e5+10;
int n;
ll a[N];
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        int ans = 0;
        for(int i=1;i<=n;++i) { 
            scanf("%lld", a+i);
            cnt = 0;
            work(a[i]);
            int sg = 0, ok = 0;
            for (int j=1; j<=cnt; ++j) {
                if (f[j]==2) ok = 1;
                else ++sg;
            }
            sg += ok;
            ans ^= sg;
        }
        puts(ans?"W":"L");
    }
}
View Code

G 队友过的

设${dp}_{n,i}$表示从点$(i,n)$走到$(0,0)$的最小期望, 那么有两种方案

一种是一直往左走遍历每扇门, 如果门开着就往下走, 如果左边全关就再绕到右边

另一种就是先右再左, 两种方案取最小就是最优期望

预处理一下概率和距离, 然后暴力$dp$, $O(n^4)$可过

#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int n,x0,k[N],pos[N][N];
bool vis[N][N];
double dp[N][N],C[N][N],dis[N][N][N],D[N][N][N];
double dfs(int n, int m) {
    double &ans = dp[n][m];
    if (vis[n][m]) return ans;
    vis[n][m] = 1;
    if (n==1) return ans = 1;
    double lx = 0, rx = 0;
    //先往左走到头再往右走
    int cnt = 0, tot = 0;
    //cnt为查看过的关上的门数, tot为当前走的距离
    auto gao = [&](int i) {
        //p为限定cnt扇门没开, 当前门开的概率
        double p = D[n][cnt][k[n]], mi = 1e18;
        for (int j=1; j<n; ++j) mi = min(mi, dfs(n-1,j)+dis[n][i][j]);
        return p*(mi+tot);
    };
    for (int i=m; i>=1; --i) {
        if (cnt+k[n]>n) break;
        lx += gao(i);
        if (i!=1) tot += 2;
        ++cnt;
    }
    if (m!=n) {
        //从1移动到m+1
        tot += m*2;
        for (int i=m+1; i<=n; ++i) {
            if (cnt+k[n]>n) break;
            lx += gao(i);
            tot += 2, ++cnt;
        }
    }
    //先往右走到头再往左走
    cnt = tot = 0;
    for (int i=m; i<=n; ++i) {
        if (cnt+k[n]>n) break;
        rx += gao(i);
        if (i!=n) tot+=2;
        ++cnt;
    }
    if (m!=1) {
        //从n走到m-1
        tot += (n-m+1)*2;
        for (int i=m-1; i>=1; --i) {
            if (cnt+k[n]>n) break;
            rx += gao(i);
            tot += 2, ++cnt;
        }
    }
    return ans=min(lx,rx);
}

void work() {
    scanf("%d%d", &n, &x0);
    for (int i=1; i<=n; ++i) scanf("%d", k+i);
    memset(vis,0,sizeof vis);
    double ans = 1e18;
    for (int i=1; i<=n; ++i) {
        double w = sqrt((x0-pos[n][i])*(x0-pos[n][i])+1);
        ans = min(ans, dfs(n,i)+w);
    }
    printf("%.20lf\n", ans);
}

int main() {
    for (int i=0; i<N; ++i) {
        C[i][0] = 1;
        for (int j=1; j<=i; ++j) {
            C[i][j] = C[i-1][j]+C[i-1][j-1];
            pos[i][j] = -i+2*j-1;
        }
    }
    for (int n=1; n<=50; ++n) {
        for (int i=1; i<=n; ++i) for (int j=1; j<n; ++j) {
            double x1 = pos[n][i], y1 = n;
            double x2 = pos[n-1][j], y2 = n-1;
            dis[n][i][j] = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
        }
        for (int k=1; k<=n; ++k) for (int cnt=0; cnt+k<=n; ++cnt) {
            D[n][cnt][k] = (C[n-cnt][k]-C[n-cnt-1][k])/C[n][k];
        }
    }
    int t;
    scanf("%d", &t);
    while (t--) work();
}
View Code

I

J 队友过的

若只有$K_{1,1}$非零, 直接输出$A$, 否则输出全零矩阵

L

cometoj原题

异或很容易处理, 绝对值可以拆开, 表示成$x-y+K\ge 0\wedge y-x+K\ge 0$

从二进制高位到低位遍历, 如果当前位$x-y+K\le -2$, 那么后面无论怎么取都是负的, 如果当前位$x-y+K\ge 2$, 那么后面无论怎么取都是正的

所以只要维护[-1,1]三种取值即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[32][3][3][2][2][2];
int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int a,b,k,w;
        scanf("%d%d%d%d", &a, &b, &k, &w);
        memset(dp,0,sizeof dp);
        dp[31][1][1][1][1][1] = 1;
        ll ans = 0;
        for (int i=30; i>=0; --i) {
            for (int u=-1; u<=1; ++u) for (int v=-1; v<=1; ++v) for (int lw=0; lw<2; ++lw) {
                for (int lx=0; lx<2; ++lx) for (int ly=0; ly<2; ++ly) {
                    ll &ret = dp[i+1][u+1][v+1][lw][lx][ly];
                    if (!ret) continue;
                    int mx = lx?a>>i&1:1, my = ly?b>>i&1:1;
                    for (int xx=0; xx<=mx; ++xx) for (int yy=0; yy<=my; ++yy) {
                        if (lw&&(xx^yy)>(w>>i&1)) continue;
                        int nu = u*2+xx-yy+(k>>i&1), nv = v*2+yy-xx+(k>>i&1);
                        if (nu<-1||nv<-1) continue;
                        nu = min(nu, 1), nv = min(nv, 1);
                        if (!i) {
                            if (nu>=0&&nv>=0) ans += ret;
                        }
                        else dp[i][nu+1][nv+1][lw&&(xx^yy)==(w>>i&1)][lx&&xx==mx][ly&&yy==my] += ret;
                    }
                }
            }
        }
        printf("%lld\n", ans);
    }
}
View Code

M

 

标签:cnt,return,int,ll,ans,ccpc,2020,online,SG
来源: https://www.cnblogs.com/fs-es/p/13707077.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有