ICode9

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

20220912--CSP-S模拟4

2022-09-12 17:30:09  阅读:189  来源: 互联网

标签:BigNum -- 20220912 len int num const include CSP


A. 石子游戏

首先了解一个叫做 \(\operatorname{Nim}\) 游戏的玩意
通常的 \(\operatorname{Nim}\) 游戏的定义是这样的:
有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”
如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)
那么有一个美妙的结论:如果石子数的异或和为 \(0\) 则后手必胜,否则先手必胜
证明:如果石子数的异或和为 \(0\) ,也即 \(a_1\oplus a_2 \oplus \cdots \oplus a_n=0\)
那么改变一个数字 \(a_i\) 使原式异或和不为 \(0\) ,设改变后的二进制表示为 \(\Delta_2\)
那么一定存在某个 \(a_j\) 在 \(\Delta_2\) 的最高位上是 \(1\)(否则无法得到这个 \(1\) )
改变这个 \(a_j\) 即可
对于本题只要将所有 \(a_i\) 模 \(x+1\) 求异或和是否为 \(0\)

image

关于数组 \(f\) :
题解里面预处理的 \(f\) 数组是基于位运算的,\(f[i][j]\) 是由第 \(j+1\) 位加一个 \(1\)转移过来的,
然后这一段区间使用了状压的思想枚举了子集算出的和累加的贡献
把后面的式子拆开就可以发现,累加的次数刚好为 \([0,2^j−1]\)
这还表明了一个问题,就是只有偶数段才会做贡献。别着急问偶数段是啥,先听我说
刚才说累加的次数只有 \(2^j\) 次,而 \(2^{j+1}=2^j\times 2\)是累加次数的二倍
再看累加的起点终点,不难发现,如果把 \(2^j\) 长度称为一段,那么 \(2^{j+1}\) 就是两段,分开考虑这两段。
因为累加的起点在第二段开头也就是 \(i+2^j\) 而不是 \(i\)
所以每次加上一个 \(2^j+1\)长度的区间里面都只有第二段做出了累加的贡献,所以说只有偶数段才做贡献。
关于答案计算:
对于枚举每一个 \(x+1\) ,我们枚举一个 \(j\), 显然只会枚举到 \(\log_2(x)\)
然后我们再枚举一下可能的 \(k\) 找到一段要计算的区间 \([l,r]\) ,使用向下取整的方式找到距离 \(r\) 最近的 \(l+2^{j+1}\)
这一段的贡献可以用预处理出的数组直接做后缀和求出
然后考虑区间 \([l+2^{j+1},r]\) ,这段区间如果是在奇数区间,则不用计算单独的贡献,因为他没有
如果有一些在偶数区间或者被偶数区间包含,就需要使用前缀和求出贡献,很好求,直接最右端减去最左端就行
算出的这个数如果是奇数,就会有贡献,给计数器上的 \(j\) 位异或一个 \(1\)
因为要计算总和,现在枚举的是区间,需要找的是所有可能区间的答案的和是否为奇数
所以是异或,不是与,如果两个区间都是奇数那答案就会变成偶数。
这样就差不多了。

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=501000,INF=1099588621776;
int n,cnt[WR<<1];
int dp[WR<<1][55];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
signed main(){
    freopen("stone.in","r",stdin);
    freopen("stone.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++) cnt[read()]++;
    for(int i=1;i<=n;i++) cnt[i]+=cnt[i-1];
    for(int i=n;i!=-1;i--)
        for(int j=0;j<=log2(n-i+1);j++)
            dp[i][j]=dp[min(i+(1<<(j+1)),n)][j]+cnt[min(i+(1<<(j+1))-1,n)]-cnt[i+(1<<j)-1];
    for(int y=2;y<=n+1;y++){
        int tmp=0;
        bool flag=0;
        for(int j=0;j<=log2(y-1);j++){
            for(int k=0;k*y<=n;k++){
                int l=k*y,r=min((k+1)*y-1,n),flr=(r-l+1)>>(j+1);
                bool lim=(l+flr*(1<<(j+1))+(1<<j)<=r);
                if((dp[l][j]-dp[l+flr*(1<<(j+1))][j]+lim*(cnt[r]-cnt[l+flr*(1<<(j+1))+(1<<j)-1]))&1) tmp^=1<<j;
            }
            if(tmp){flag=1;break;}
        }
        printf(flag?"Alice ":"Bob ");
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

C. 黑客

首先如果你像我一样上来先一眼线性筛了 \(\mu\) 函数准备莫反那么恭喜你
你假了
咳,正经的做法非常显然
对于一组数据 \([a,b],[c,d]\)
针对每一个分数,设为 \(\frac{p}{q}\)
我们都可以找到 \(l_1,r_1,l_2,r_2\) 使得 \(l_1p>=a\; ,\; r_1p<=b\) 且 \(l_2q>=c\; ,\; r_2q<=d\)
那么分数可以变成 \(\frac{\lambda p}{\mu q}\) ,\(\lambda \in [l_1,r_1]\; ,\; \mu\in [l_2,r_2]\)
显然地,当 \(\lambda=\mu\) 的时候可以约分,这样的 \((\lambda,\mu)\) 共有 \(\min(r_1,r_2)-\max(l_1,l_2)+1\) 组

点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=501000,INF=1099588621776,mod=1e9+7;
int a,b,c,d;
int ans;
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
int gcd(int a,int b){
    if(!b) return a;
    return gcd(b,a%b);
}
signed main(){
    freopen("hacker.in","r",stdin);
    freopen("hacker.out","w",stdout);
    a=read(),b=read(),c=read(),d=read();
    for(int i=1;i<=998;i++){
        for(int j=1;j<=999-i;j++){
            if(gcd(i,j)!=1) continue;
            int l=max((int)ceil((double)a/i),(int)ceil((double)c/j));
            int r=min((int)floor((double)b/i),(int)floor((double)d/j));
            // printf("%lld %lld\n",l,r);
            if(r>=l) ans=(ans+(i+j)*(r-l+1)%mod)%mod;
        }
    }
    printf("%lld\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

D. 黑客(续)

无耻的高精度题
无耻的卡常题
不是这么做真的有任何必要吗???
考虑一个数位 \(\operatorname{DP}\)
设当前数字选择状态为 \(S\) ,当前递归到了第 \(pos\) 位
然后非常显然地就可以写出代码

这个只有90分
//RNM高精度!!!!!!退钱!!!!!!!
#include<cstdio>
#include<cstring>
#include<string>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=510,INF=1099588621776,mod=1e17;
struct BigNum{
    int num[70],len;
    void clr(){memset(num,0,sizeof(num));len=0;}
    BigNum operator =(int val){
        clr();
        while(val){
            num[++len]=val%mod;
            val/=mod;
        }
        return *this;
    }
    BigNum operator +(const BigNum &b)const{
        BigNum res=*this;
        for(int i=1;i<=b.len;i++){
            res.num[i]+=b.num[i];
            res.num[i+1]+=res.num[i]/mod;
            res.num[i]%=mod;
        }
        while(res.num[++res.len]){
            res.num[res.len+1]+=res.num[res.len]/mod;
            res.num[res.len]%=mod;
        }
        while(res.len>1&&!res.num[res.len]) res.len--;
        return res;
    }
    BigNum operator +=(const BigNum &b){*this=*this+b;return *this;}
    BigNum operator *(const int &b)const{
        BigNum res=*this;
        for(int i=1;i<=res.len;i++) res.num[i]*=b;
        for(int i=1;i<=res.len;i++){
            res.num[i+1]+=res.num[i]/mod;
            res.num[i]%=mod;
        }
        while(res.num[++res.len]){
            res.num[res.len+1]+=res.num[res.len]/mod;
            res.num[res.len]%=mod;
        }
        while(res.len>1&&!res.num[res.len]) res.len--;
        return res;
    }
    BigNum operator *=(const int &b){*this=*this*b;return *this;}
    void print(){
        printf("%lld",num[len]);
        for(int i=len-1;i>=1;i--){
            if(!len) break;
            printf("%017lld",num[i]);
        }
        printf("\n");
    }
};
int n,m,k;
int ban[WR];
pair<BigNum,BigNum>dp[WR][(1<<9)+10];
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-'0';
        ch=getchar();
    }
    return s*w;
}
pair<BigNum,BigNum> dfs(int pos,int S){
    if(dp[pos][S].first.num[1]>=0) return dp[pos][S];
    if(pos>n){
        BigNum tmp1,tmp2;
        tmp1=1,tmp2=0;
        return dp[pos][S]=make_pair(tmp1,tmp2);
    }
    dp[pos][S].first=0;
    for(int i=1;i<=k;i++){
        if(!(S&ban[i])){
            pair<BigNum,BigNum>res=dfs(pos+1,S|(1<<(i-1)));
            dp[pos][S].first+=res.first;
            res.first=res.first*i,res.second=res.second*10;
            dp[pos][S].second=dp[pos][S].second+res.first+res.second;
        }
    }
    return dp[pos][S];
}
signed main(){
    freopen("hacker2.in","r",stdin);
    freopen("hacker2.out","w",stdout);
    n=read(),m=read(),k=read();
    int tmp=(1<<k);
    for(int i=1;i<=n+1;i++){
        for(int j=0;j<tmp;j++){
            dp[i][j].first=-1;
        }
    }
    for(int i=1;i<=m;i++){
        int a=read(),b=read();
        ban[a]|=(1<<(b-1));
    }
    pair<BigNum,BigNum>ans;
    ans=dfs(1,0);
    ans.first.print();ans.second.print();
    fclose(stdin);
    fclose(stdout);
    return 0;
}
又强又可爱的Eafoo的AC






#include <cstdio>
#include <cctype>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
#include <vector>
#include <cassert>
%:pragma GCC optimize(3)
using namespace std;

typedef long long ll;

int read() {
    int x = 0;
    char c;
    bool f = 0;
    while (!isdigit(c = getchar())) {
        if (c == '-') f = 1;
    }
    do {
        x = (x << 1) + (x << 3) + (c ^ 48);
    } while (isdigit(c = getchar()));
    if (f) return -x;
    return x;
}

const int maxn = 5e2 + 1, maxs = (1 << 9);

struct Int {
    ll num[80];
    Int() { num[0] = 1; }
    const ll len = 1e17;
    void Init() { memset(num, 0, sizeof num); num[0] = 1; }
    Int operator +(const Int &b) const {
        Int c;
        c.Init();
        c.num[0] = max(num[0], b.num[0]);
        for (int i = 1; i <= c.num[0]; ++i) {
            c.num[i] += num[i] + b.num[i];
            if (c.num[i] >= len) {
                c.num[i] -= len;
                ++c.num[i + 1];
            }
        }
        if (c.num[c.num[0] + 1] > 0) ++c.num[0];
        return c;
    }
    Int operator *(int b) const {
        Int c; 
        c.Init();
        c.num[0] = num[0] + 1;
        for (int i = 1; i <= c.num[0]; ++i) {
            c.num[i] += num[i] * b;
            c.num[i + 1] += c.num[i] / len;
            c.num[i] %= len;
        }
        while (c.num[c.num[0]] == 0 && c.num[0] > 1) --c.num[0];
        return c;
    }
    void operator +=(const Int &b) {
        num[0] = max(num[0], b.num[0]);
        for (int i = 1; i <= num[0]; ++i) {
            num[i] += b.num[i];
            if (num[i] >= len) {
                num[i] -= len;
                ++num[i + 1];
            }
        }
        if (num[num[0] + 1] > 0) ++num[0];
    }
    void operator *=(int b) {
        ++num[0];
        for (int i = 1; i <= num[0]; ++i) {
            num[i] += num[i] * (b - 1);
            num[i + 1] += num[i] / len;
            num[i] %= len;
        }
        while (num[num[0]] == 0 && num[0] > 1) --num[0];
    }
    void put() {
        printf("%lld", num[num[0]]);
        for (int i = num[0] - 1; i; --i) printf("%017lld", num[i]);
    }
    void putln() { put(), putchar('\n'); }
};

bool ok[maxs][10];
Int f[2][maxs];
Int sum[2][maxs];
bool ban[10][10];

signed main() {
    #ifndef DEBUG
    freopen("hacker2.in", "r", stdin);
    freopen("hacker2.out", "w", stdout);
    #endif
    int n = read(), m = read(), p = read();
    for (int i = 1; i <= m; ++i) {
        int a = read(), b = read();
        ban[b][a] = 1; // b前 没有 a
    }
    int Max = 1 << p;
    for (int i = 0; i < Max; ++i) {
        for (int j = 1; j <= p; ++j) {
            bool f = 0;
            for (int k = 1; k <= p; ++k) {
                if (!((i >> (k - 1)) & 1)) continue;
                if (ban[j][k]) { f = 1; break; }
            }
            if (!f) ok[i][j] = 1;
        }
    }
    int pi = 0;
    f[pi][0].num[1] = 1;
    for (int i = 1; i <= n; ++i) {
        pi ^= 1;
        for (int j = 0; j < Max; ++j) f[pi][j].Init(), sum[pi][j].Init();
        for (int j = 0; j < Max; ++j) {
            for (int k = 1; k <= p; ++k) {
                if (!ok[j][k]) continue;
                int s = j | (1 << (k - 1));
                f[pi][s] += f[pi ^ 1][j];
                sum[pi][s] += sum[pi ^ 1][j] * 10;
                sum[pi][s] += f[pi ^ 1][j] * k;
            }
        }
    }
    Int ans, ans1;
    ans.Init(), ans1.Init();
    for (int i = 0; i < Max; ++i) ans += f[pi][i], ans1 += sum[pi][i];
    ans.putln();
    ans1.putln();
}   

标签:BigNum,--,20220912,len,int,num,const,include,CSP
来源: https://www.cnblogs.com/WintersRain/p/16686277.html

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

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

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

ICode9版权所有