CSU 1720 How to Get 2^n (大数+hash)

题意:给你10W个数字,每个数都是大数,范围是1到10^30,然后问你有多少种方法,每次选取两个数,两个数的和是2的幂次

题解:10的30次大约是2的100次,所以先预处理2的102次,然后就是每次输入一个大数,枚举2的幂次去减它,然后去map里找有多少个解,其实是个很简单的思路,但是我却一直写炸,主要是大数的模板太差,会T,加上我智商下线,开了很大的数组去存输入的内容,结果实力T。

其实一边输入,然后转化为大数,然后枚举2的幂次,相减,然后hash,去map里面查,然后累计求和,然后把输入hash,放进map里,这样就好了

问qwb神犇要了新的姿势的大数模板otz,感觉十分之屌,跑得飞快

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
//#define   MAXN          500005
#define   maxnode       105
#define   sigma_size    2
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
const double pi    = acos(-1.0);
const double inf   = 1e18;
const double eps   = 1e-9;
const LL     mod   = 1e9+7;
const ull    mx    = 1e9+7;

/*****************************************************/
inline void RI(int &x) {
      char c;
      while((c=getchar())<'0' || c>'9');
      x=c-'0';
      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

const int MX = 10;//一共可以表示长度MX*DLEN的
const int maxn = 9999;
const int DLEN = 4;//一个int里面放多少个数字

char ret[105];
class Big {
public:
    int a[MX], len;
    Big(const int b = 0) {
        int c, d = b;
        len = 0;
        memset(a, 0, sizeof(a));
        while(d > maxn) {
            c = d - (d / (maxn + 1)) * (maxn + 1);
            d = d / (maxn + 1);
            a[len++] = c;
        }
        a[len++] = d;
    }
    Big(const char *s) {
        int t, k, index, L, i;
        memset(a, 0, sizeof(a));
        L = strlen(s);
        len = L / DLEN;
        if(L % DLEN) len++;
        index = 0;
        for(i = L - 1; i >= 0; i -= DLEN) {
            t = 0;
            k = i - DLEN + 1;
            if(k < 0) k = 0;
            for(int j = k; j <= i; j++) {
                t = t * 10 + s[j] - '0';
            }
            a[index++] = t;
        }
    }
    Big operator/(const int &b)const {
        Big ret;
        int i, down = 0;
        for(int i = len - 1; i >= 0; i--) {
            ret.a[i] = (a[i] + down * (maxn + 1)) / b;
            down = a[i] + down * (maxn + 1) - ret.a[i] * b;
        }
        ret.len = len;
        while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
        return ret;
    }
    bool operator>(const Big &T)const {
        int ln;
        if(len > T.len) return true;
        else if(len == T.len) {
            ln = len - 1;
            while(a[ln] == T.a[ln] && ln >= 0) ln--;
            if(ln >= 0 && a[ln] > T.a[ln]) return true;
            else return false;
        } else return false;
    }
    Big operator+(const Big &T)const {
        Big t(*this);
        int i, big;
        big = T.len > len ? T.len : len;
        for(i = 0; i < big; i++) {
            t.a[i] += T.a[i];
            if(t.a[i] > maxn) {
                t.a[i + 1]++;
                t.a[i] -= maxn + 1;
            }
        }
        if(t.a[big] != 0) t.len = big + 1;
        else t.len = big;
        return t;
    }
    Big operator-(const Big &T)const {
        int i, j, big;
        bool flag;
        Big t1, t2;
        if(*this > T) {
            t1 = *this;
            t2 = T;
            flag = 0;
        } else {
            t1 = T;
            t2 = *this;
            flag = 1;
        }
        big = t1.len;
        for(i = 0; i < big; i++) {
            if(t1.a[i] < t2.a[i]) {
                j = i + 1;
                while(t1.a[j] == 0) j++;
                t1.a[j--]--;
                while(j > i) t1.a[j--] += maxn;
                t1.a[i] += maxn + 1 - t2.a[i];
            } else t1.a[i] -= t2.a[i];
        }
        t1.len = big;
        while(t1.a[t1.len - 1] == 0 && t1.len > 1) {
            t1.len--;
            big--;
        }
        if(flag) t1.a[big - 1] = 0 - t1.a[big - 1];
        return t1;
    }
    int operator%(const int &b)const {
        int i, d = 0;
        for(int i = len - 1; i >= 0; i--) {
            d = ((d * (maxn + 1)) % b + a[i]) % b;
        }
        return d;
    }
    Big operator*(const Big &T) const {
        Big ret;
        int i, j, up, temp, temp1;
        for(i = 0; i < len; i++) {
            up = 0;
            for(j = 0; j < T.len; j++) {
                temp = a[i] * T.a[j] + ret.a[i + j] + up;
                if(temp > maxn) {
                    temp1 = temp - temp / (maxn + 1) * (maxn + 1);
                    up = temp / (maxn + 1);
                    ret.a[i + j] = temp1;
                } else {
                    up = 0;
                    ret.a[i + j] = temp;
                }
            }
            if(up != 0) {
                ret.a[i + j] = up;
            }
        }
        ret.len = i + j;
        while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;
        return ret;
    }
    ull print() {
        ull ret=0;
        for(int i=len-1;i>=0;i--) ret=ret*mx+a[i];
        return ret;
    }
}pow2[105],ss;
map<ull,int> ma;
char s[105];
void init(){
    pow2[0]=1;
    for(int i=1;i<=103;i++) pow2[i]=pow2[i-1]*2;
}
int main(){
    //freopen("test.txt","r",stdin);
    int t;
    cin>>t;
    init();
    while(t--){
        int n;
        cin>>n;
        ma.clear();
        LL ans=0;
        for(int i=0;i<n;i++){
            scanf("%s",s);
            int len;
            ss=s;
            for(int j=103;j>=1;j--){
                if(pow2[j]>ss){
                    Big cnt=pow2[j]-ss;
                    ull temp=cnt.print();
                    if(ma.count(temp)) ans+=ma[temp];
                }
            }
            ull tmp=ss.print();
            if(!ma.count(tmp)) ma[tmp]=0;
            ma[tmp]++;
            //cout<<ma[ss[i]]<<" "<<ss[i]<<endl;
        }
        cout<<ans<<endl;
    }
    return 0;
}

/**************************************************************
    Problem: 1720
    User: 1403mashaonan
    Language: C++
    Result: Accepted
    Time:5640 ms
    Memory:4272 kb
****************************************************************/
时间: 2025-01-08 03:20:08

CSU 1720 How to Get 2^n (大数+hash)的相关文章

Oracle 学习之 数据仓库(二) Dimension 的理解

在数据仓库中,有事实表.维度表两个概念. 事实表是数据仓库结构中的中央表,它包含联系事实与维度表的数字度量值和键.事实数据表包含描述业务(例如产品销售)内特定事件的数据. 维度表是维度属性的集合.是分析问题的一个窗口.是人们观察数据的特定角度,是考虑问题时的一类属性,属性的集合构成一个维. 如图示 我们以sh用户下的sales表和times表来看, SALES为事实表 SQL> desc sales  Name    Null?    Type  ------------------------

csu 1556: Jerry&#39;s trouble(大数取模)

题意:求出1^m+2^m+...n^m 思路:直接套用模板 #include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<stdlib.h> #include<algorithm> #include<queue> #include<stack> #include<ctype.h> #define LL l

[csu/coj 1080]划分树求区间前k大数和

题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数和. 划分树: [1  6  3  8  5  4  7  2] [6  8  5  7][1  3  4  2] [8  7][6  5][3  4][1  2] [8][7][6][5][4][3][2][1] 把快排的结果从上至下依次放入线段树,就构成了划分树,划分的意思就是选定一个数,把原序

csu 1967 二项式概率

传送门:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1967 N最大50,其实不会超int,一开始WA,以为是精度大数溢出什么的问题.在这上面浪费了很多时间. 忽略了另外一种情况.当n为偶数的时候,如果v2获得了n/2的票,v1无论如何都赢不了,所以在第一个特判出了这个问题,没有特判全.如果没有捕捉到这个点,在下面计算概率不满足情况下,输出的是“ PATIENCE, EVERYONE!"的情况,错误. 所以还是要严谨啊. #include

[csu/coj 1619] 递归

题意:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1619 思路:由于式子具有递归的性质,考虑递归解,中间结果会超64位int,需用大数.另外自己写了个分数类,见代码. 1 #pragma comment(linker, "/STACK:10240000,10240000") 2 3 #include <iostream> 4 #include <cstdio> 5 #include <algorith

CSU 1804: 有向无环图(拓扑排序)

http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1804 题意:…… 思路:对于某条路径,在遍历到某个点的时候,之前遍历过的点都可以到达它,因此在这个时候对答案的贡献就是∑(a1 + a2 + a3 + ... + ai) * bv,其中a是之前遍历到的点,v是当前遍历的点. 这样想之后就很简单了.类似于前缀和,每次遍历到一个v点,就把a[u]加给a[v],然后像平时的拓扑排序做就行了. 1 #include <bits/stdc++.h>

CSU 1111: 三家人【有趣的思维题】

1111: 三家人 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 2241  Solved: 874 [Submit][Status][Web Board] Description 有三户人家共拥有一座花园,每户人家的太太均需帮忙整理花园.A 太太工作了5 天,B 太太则工作了4 天,才将花园整理完毕.C 太太因为正身怀六甲无法加入她们的行列,便出了90元.请问这笔钱如何分给A.B 二位太太较为恰当?A 应得多少元?90/(5+4)*5=$50

CSU 1112: 机器人的指令【模拟题】

1112: 机器人的指令 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 1858  Solved: 682 [Submit][Status][Web Board] Description 数轴原点有一个机器人.该机器人将执行一系列指令,你的任务是预测所有指令执行完毕之后它的位置. ·LEFT:往左移动一个单位 ·RIGHT: 往右移动一个单位 ·SAME AS i: 和第i 条执行相同的动作.输入保证i 是一个正整数,且不超过之前执行指令数 In

最短的计算大数乘法的c程序

#include <stdio.h> char s[99],t[99]; int m,n; void r(int i,int c) { int j=0,k=i; while(k)c+=s[j++]*t[k---1]; if(i)r(i-1,c/10); printf("%d",c%10); } void main() { gets(s);gets(t); while(s[n])s[n++]-=48; while(t[m])t[m++]-=48; r(m+n-1,0); }