• AtCoder Grand Contest 047 部分题解


    本题解包含 (A,B) 以及 (E) 的前 (800) 分。

    AGC047A

    大家都知道直接模拟是肯定不行的。感觉很难做?

    然后我们要注意“小数点后最多(9)位”这个条件,同时乘上 (10^9) ,它们就都变成了整数。

    可以发现,如果其中两个数原是 (a,b),现是 (a',b')(a imes b) 为整数,则 (a' imes b') 能被 (10^{18}) 整除。对每个数,记一下因数 (2)(5) 的数量,拿一个桶存下来,最后枚举 (2)(5) 的数量,统计一下就好了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define mit map<int,int>::iterator
    #define sit set<int>::iterator
    #define itrm(g,x) for(mit g=x.begin();g!=x.end();g++)
    #define itrs(g,x) for(sit g=x.begin();g!=x.end();g++)
    #define ltype int
    #define rep(i,j,k) for(ltype(i)=(j);(i)<=(k);(i)++)
    #define rap(i,j,k) for(ltype(i)=(j);(i)<(k);(i)++)
    #define per(i,j,k) for(ltype(i)=(j);(i)>=(k);(i)--)
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mpr make_pair
    #define pb push_back
    #define fastio ios::sync_with_stdio(false)
    const int inf=0x3f3f3f3f,mod=1000000007;
    const double pi=3.1415926535897932,eps=1e-6;
    void chmax(int &x,int y){if(x < y) x = y;}
    void chmin(int &x,int y){if(x > y) x = y;}
    int n;ll pw[20],num[200005],ans;
    string s[200005];
    ll t[105][105];
    int main()
    {
        pw[0] = 1;rep(i,1,18) pw[i] = pw[i - 1] * 10;
        fastio;
        cin>>n;
        rep(i,1,n) {
            cin>>s[i];
            int pos = -1;
            rap(j,0,s[i].size()) if(s[i][j] == '.') pos = j;
            if(pos == -1) pos = s[i].size();
            rap(j,0,pos) num[i] += (s[i][j] - '0') * pw[pos + 8 - j];
            rap(j,pos+1,s[i].size()) num[i] += (s[i][j] - '0') * pw[9 - (j - pos)];
            //cout<<num[i]<<endl;
        }
        rep(i,1,n) {
            int num2 = 0,num5 = 0;
            while(num[i] % 2 == 0) num2++,num[i] /= 2;
            while(num[i] % 5 == 0) num5++,num[i] /= 5;
            if(num2 >= 9 && num5 >= 9) ans--;
            t[num2][num5]++;
        }
        rep(two,0,64) rep(fiv,0,64) {
            int nedtwo = max(18 - two, 0);
            int nedfiv = max(18 - fiv, 0);
            rep(k,nedtwo,64) rep(l,nedfiv,64) ans += t[two][fiv] * t[k][l];
        }
        cout<<ans / 2;
        return 0;
    }
    

    AGC047B

    容易发现,一个串 (S) 能被另外一个串 (T) 形成,当且仅当:(T) 除去第一个字符后,是 (S) 的后缀,且 (T) 的第一个字符在 (S) 的前面部分出现了。

    这样很容易想到,把所有串反转后插到一棵 (Trie) 里。

    实现起来还是有点困难的。

    可以令 (suf_i) 表示第 (i) 个节点下面单词结尾的个数,(suf2_{i,j}) 表示从第 (i) 个节点往下走,走到一个单词结尾 (w) ,路径上至少经过一个字符 (j)(w) 的数量。

    对于每个串,设长度为 (len) ,先走 (len - 1) 步,走不到就一定不合法(其实不用判断,一开始就把所有的串插入进来了,所以一定能走到),然后现在走到了结点 (cur) ,对 (cur)每个儿子(son),把答案增加 (suf2_{son,lastchar})。最后去掉重复计算的。

    注意不能直接 (suf2_{cur,lastchar}),不然这组数据会挂掉:

    2
    ewq
    eewq
    

    "ewq" 会把 "eewq"统计进去,去重处理之后,会输出 (2)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define mit map<int,int>::iterator
    #define sit set<int>::iterator
    #define itrm(g,x) for(mit g=x.begin();g!=x.end();g++)
    #define itrs(g,x) for(sit g=x.begin();g!=x.end();g++)
    #define ltype int
    #define rep(i,j,k) for(ltype(i)=(j);(i)<=(k);(i)++)
    #define rap(i,j,k) for(ltype(i)=(j);(i)<(k);(i)++)
    #define per(i,j,k) for(ltype(i)=(j);(i)>=(k);(i)--)
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mpr make_pair
    #define pb push_back
    #define fastio ios::sync_with_stdio(false)
    const int inf=0x3f3f3f3f,mod=1000000007;
    const double pi=3.1415926535897932,eps=1e-6;
    void chmax(int &x,int y){if(x < y) x = y;}
    void chmin(int &x,int y){if(x > y) x = y;}
    int n;ll ans;
    string s[200005];
    int son[1000005][27],tag[1000005];
    char typ[1000005];
    int ex[1000005][27],suf1[1000005],suf2[1000005][27];/*ex 是无用数组*/
    int num;
    //root is 0
    void ins(string s){
        int cur = 0;
        rap(i,0,s.size()){
            if(!son[cur][s[i] - 'a']) {
                son[cur][s[i] - 'a'] = ++num;
                typ[num] = s[i];
                cur = num;
            }
            else cur = son[cur][s[i] - 'a'];
        }
        tag[cur]++;
    }
    void dfs(int x){
        ex[x][typ[x] - 'a'] ++;//无用语句
        suf1[x] += tag[x];
        rep(i,0,25){
            if(son[x][i]) {
                dfs(son[x][i]);
                suf1[x] += suf1[son[x][i]];
                rep(j,0,25) {ex[x][j] += ex[son[x][i]][j]; suf2[x][j] += suf2[son[x][i]][j];}
            }
        }
        rep(ch,0,25) {
            if(typ[x] == ch + 'a') suf2[x][ch] = suf1[x];
        }
        //cout<<x<<' '<<typ[x]<<' '<<suf2[x][2]<<'
    ';
    }
    int main()
    {
        fastio;
        cin>>n;
        rep(i,1,n) {cin>>s[i];reverse(s[i].begin(),s[i].end());}
        rep(i,1,n) ins(s[i]);
        dfs(0);
        rep(i,1,n) {
            //walk
            int nwlen = (int)s[i].size() - 1;
            int cur = 0;
            bool flg = 0;
            rap(j,0,nwlen){
                int to = son[cur][s[i][j] - 'a'];
                if(!to) {flg = 1;break;}
                cur = to;
            }
            if(flg) continue;
            //cout<<i<<' '<<cur<<'
    ';
            char lst = s[i].back();
            rep(ch,0,25) if(son[cur][ch]) ans += suf2[son[cur][ch]][lst - 'a'];
            //cout<<lst<<' '<<suf2[cur][lst - 'a']<<'
    ';
        }
        ans -= n;
        cout<<ans<<'
    ';
        return 0;
    }
    

    AGC047E

    本人思路有点奇怪,希望大家能看懂。。。

    为了解释清晰一点,令 (N = 200000)

    (A,B leq 10) 看起来比较好搞。

    我们想办法把 (a_{N - 1}) 搞成 (1) 备用。

    考虑把 (a_2) 加上 (A)(B) ,这样就是 (A imes B)

    于是在 (a_3) 中存上 (B) 的副本,然后把 (a_0) 加上 (B) ,变成 (A + B) ,这样只要循环(10)次,每次当 (a_0 < a_1) 时,把 (a_2) 加上 (B),然后把(a_1) 加上 (1) ,就达成了目标。

    但是直接"加上 (B)"也不好做,因为没有"if"。

    然后只能把 (B) 拆成 (B)(1) 加在一起了。又要套一个(10)次的循环,每次判断是不是要加这个 (1)

    那么这个 (1) 什么时候可以加呢?当然是

    a[1] < a[0] && j - 1 < a[3](j 为循环变量)
    

    用一个位置 (a_{4}) 来储存 (j),重头戏是如何处理与运算

    我们用 (a_{N - 2}) 来储存 (a_1 leq a_0)(a_{N - 3}) 来储存 (a_{4} leq a_3)(a_{N - 4}) 来储存 (a_{N - 2} + a_{N - 3})。只要 (1 < a_{N - 4}) 成立,那么上式为真。这样就可以做了。

    还有一个小问题:(A,B) 有可能等于 (0),如何确保 (a_{N - 1}) 等于 (1)

    如果 (A)(B) 至少一个大于 (0),令 (a_{N - 1} = (A > 0) || (B > 0)) 即可(“与”会了,“或”应该也会了)(注:我一开始傻了,好像直接判断 (A+B > 0) 就 ok 了...)

    否则,无论怎样操作,都不可能搞出任何一个大于 (0) 的数,算出的答案一定是 (0),我们也就不用管了。

    程序中出现了各种各样奇怪的下标,有些特殊的做了注释,其他的自行转换一下吧。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define mit map<int,int>::iterator
    #define sit set<int>::iterator
    #define itrm(g,x) for(mit g=x.begin();g!=x.end();g++)
    #define itrs(g,x) for(sit g=x.begin();g!=x.end();g++)
    #define ltype int
    #define rep(i,j,k) for(ltype(i)=(j);(i)<=(k);(i)++)
    #define rap(i,j,k) for(ltype(i)=(j);(i)<(k);(i)++)
    #define per(i,j,k) for(ltype(i)=(j);(i)>=(k);(i)--)
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mpr make_pair
    #define pb push_back
    #define fastio ios::sync_with_stdio(false)
    const int inf=0x3f3f3f3f,mod=1000000007;
    const double pi=3.1415926535897932,eps=1e-6;
    void chmax(int &x,int y){if(x < y) x = y;}
    void chmin(int &x,int y){if(x > y) x = y;}
    string buf[44444];
    int top;
    void Puts(string s){buf[++top] = s;}
    int main()
    {
        //freopen("code.txt","w",stdout);
        //注意这四行 a[2] 是当作 0 来用的
        Puts("< 2 0 199999");
        Puts("< 2 1 747");
        Puts("+ 199999 747 748");
        Puts("< 2 748 199999");//199999 先存 A>0, 747 748 这两个下标分别用来存 B>0 和 (A>0) + (B>0),再把 ((A>0) + (B>0)) > 0 存回 199999
        Puts("+ 3 1 3");//a[3] = B
        Puts("+ 0 1 0");//a[0] += B
        rep(i,1,10) {
            Puts("< 1 0 199998");//a[1] < a[0]
            Puts("+ 234 123 4");//清空
            rep(j,1,10){
                Puts("< 4 3 199997");//j - 1 < a[3]
                Puts("+ 199998 199997 199996");
                Puts("< 199999 199996 199995");
                Puts("+ 2 199995 2");//统计答案
                Puts("+ 4 199999 4");//循环变量增加
            }
            Puts("+ 1 199999 1");//循环变量增加
        }
        printf("%d
    ",top);
        rep(i,1,top) printf("%s
    ",buf[i].c_str());
    }
    
  • 相关阅读:
    MySQL常用函数介绍
    SQL语法基础之DROP语句
    MySQL常见报错汇总
    SQL语法基础之SELECT
    SQL语法基础之ALTER语句
    OpenStack技术栈-OpenStack的基础原理概述
    体验Hadoop3.0生态圈-CDH6.1时代的来临
    Windows下强制删除文件或文件夹(解除文件占用/Unlock)
    foreach Transform 同时chils.setParent引起的bug
    CharacterController平滑移动到某点
  • 原文地址:https://www.cnblogs.com/yz-beacon-cwk/p/13470138.html
Copyright © 2020-2023  润新知