zoukankan      html  css  js  c++  java
  • 洛谷 CF898F Restoring the Expression

    Description

    CF898F Restoring the Expression

    Solution

    很明显的一道哈希题,那么我们考虑哈希能否支持加法。

    我们通过列举大量式子发现,普通的哈希是不行的,但是我们换一个乘数,也就是令 (Base = 10),那么是不是就可以支持加法了呢。

    但是这样一来,冲突的概率就大了很多,所以要双哈希,而且由于是 CF 的题这道题非常毒瘤的把 (998244353)(1000000007) 等常见模数全部卡掉了 (QwQ),恶心至极。所以要换一些模数。

    然后就是具体过程。

    我们可以枚举等号的位置,假设等号后面的数长为 (len),由于加法最多进一位,所以加号前的数长度为 (len)(len - 1)加号后面的数同理。

    另外注意这道题还要判前导 0。

    这道题最麻烦的就是边界的处理,我整整做了一个晚上啊啊啊啊啊啊啊。

    Code

    (有注释)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ll long long
    
    using namespace std;
    
    const ll N = 1e6 + 10;
    const ll mod1 = 1e9 + 21;//双哈希模数
    const ll mod2 = 1e9 + 33;
    ll n, pos1 = N, pos2 = N;//pos1: 加号位置	pos2: 等号位置
    ll fx[N], f[N];//双哈希两个数组
    ll gx[N], g[N];
    char s[N];
    
    inline ll Hash1(ll l, ll r){//去第一个哈希值
    	return (f[r] - f[l - 1] * fx[r - l + 1] % mod1 + mod1) % mod1;
    }
    
    inline ll Hash2(ll l, ll r){//取第二个哈希值
    	return (g[r] - g[l - 1] * gx[r - l + 1] % mod2 + mod2) % mod2;
    }
    
    inline bool check(int l, int r){//判断是否有前导0,1为没有,0为有
    	if(s[l] != '0') return 1;//第一位不为0,直接返回1
    	for(int i = l + 1; i <= r; i++)
    		if(s[i] == '0') return 0;
    	return 1;
    }
    
    inline bool checkr1(int len, int n, int flag){//判断第二个加数长度为 len 或 len - 1 时,等式是否成立。flag = 0时,长度为 len - 1,flag = 1时,长度为 len
    	int l = n - (len << 1) + flag;//l 为第一个加数右边界
    	if(l < 1) return 0;
        //第一个加数 + 第二个加数 == 和
    	return ((Hash1(1, l) + Hash1(l + 1, n - len)) % mod1) == Hash1(n - len + 1, n) && check(l + 1, n - len);
    }
    
    inline bool checkr2(int len, int n, int flag){//第二个哈希
    	int l = n - (len << 1) + flag;
    	if(l < 1) return 0;
    	return ((Hash2(1, l) + Hash2(l + 1, n - len)) % mod2)== Hash2(n - len + 1, n) && check(l + 1, n - len);
    }
    
    inline bool checkl1(int len, int n, int flag){//判断第一个加数的情况,其它同上
    	int l = len + flag - 1;
    	if(l < 1) return 0;
    	return ((Hash1(1, l) + Hash1(l + 1, n - len)) % mod1) == Hash1(n - len + 1, n) && check(l + 1, n - len);
    }
    
    inline bool checkl2(int len, int n, int flag){
    	int l = len + flag - 1;
    	if(l < 1) return 0;
    	return ((Hash2(1, l) + Hash2(l + 1, n - len)) % mod2) == Hash2(n - len + 1, n) && check(l + 1, n - len);
    }
    
    inline void updater(int len, int flag){//当第二个加数符合条件时,更新加号和等号的位置
    	if(n - (len << 1) + flag < pos1) pos1 = n - (len << 1) + flag, pos2 = n - len;
    }
    
    inline void updatel(int len, int flag){//同理
    	if(len + flag - 1 < pos1) pos1 = len + flag - 1, pos2 = n - len;
    }
    
    signed main(){
    	//  freopen("a.in", "r", stdin);
    	//  freopen("a.out", "w", stdout);
    	scanf("%s", s + 1);
    	n = strlen(s + 1);
    	fx[0] = 1, gx[0] = 1;
    	for(ll i = 1; i <= n; i++){
    		fx[i] = fx[i - 1] * 10 % mod1;
    		f[i] = (f[i - 1] * 10 + s[i] - '0') % mod1;
    		gx[i] = gx[i - 1] * 10 % mod2;
    		g[i] = (g[i - 1] * 10 + s[i] - '0') % mod2;
    	}
    	for(int len = n / 3; len <= (n >> 1); len++){
    		if(!check(n - len + 1, n)) continue;//和 有前导0,直接跳过
    		if(checkr1(len, n, 0) && checkr2(len, n, 0)) updater(len, 0);//第二个加数长度为 len - 1
    		if(checkr1(len, n, 1) && checkr2(len, n, 1)) updater(len, 1);//第二个加数长度为 len
    		if(checkl1(len, n, 0) && checkl2(len, n, 0)) updatel(len, 0);//第一个加数长度为 len - 1
    		if(checkl1(len, n, 1) && checkl2(len, n, 1)) updatel(len, 1);//第二个加数长度为 len
    	}
    	for(ll i = 1; i <= pos1; i++)//输出
    		putchar(s[i]);
    	putchar('+');
    	for(ll i = pos1 + 1; i <= pos2; i++)
    		putchar(s[i]);
    	putchar('=');
    	for(ll i = pos2 + 1; i <= n; i++)
    		putchar(s[i]);
    	puts("");
    	return 0;
    }
    

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15291432.html

  • 相关阅读:
    来自风湿病研究院RA患者队列研究显示, RA日常诊治时特别是早期RA患者成功维持新ACR/EULAR缓解标准能获
    系列超声发现脊柱关节炎附着点处新骨形成
    超声(PDUS)能否容易检出侵蚀?比较PDUS与microCT对正常人群和RA患者小关节生理和皮质断裂的评价
    根据ACR/EULAR 2010 标准定义RA放射学侵蚀病变
    比较依那西普和柳氮磺胺吡碇治疗早期中轴脊柱关节炎1年后的停药缓解率和缓解时间-ESTHER试验的2年数据
    Matlab Computer Vision and Pattern Recognition toolbox
    vi/vim 命令手册(初级篇)
    GCC设定include和库路径(转载)
    linux 下查找文件或者内容常有命令
    svn命令在linux下的使用
  • 原文地址:https://www.cnblogs.com/xixike/p/15291432.html
Copyright © 2011-2022 走看看