• 2020年常熟理工学院第一届线上ACM选拔赛题解


    本次题目难度顺序基本从难到易,在这里非常感谢出题组同学的真情付出。此博客原文地址:https://www.cnblogs.com/BobHuang/p/12610795.html

    1.6195: Trojke II

    这个题目是4140: Trojke的一个扩展,在这个题目里由于可以匹配的棋子很多,我们应该想的是去遍历这个棋盘的所有线。这就是格点问题:从(0,0)到(x,y)的线段,经过的格点数目是gcd(x,y)+1。比如(3,5)是两个;(2,4)就是3个,因为过了(1,2);(8,20)是5个,因为还过了(2,5)、(4,10)、(6,15)。这个的证明可以从相似三角形下手,比较简单。
    所以这个题目我们预处理出所有的线就可以了,具体实现思路可以看代码。我们可以查一条线上的点的个数x,然后C(x,3)就是当前点构成三胞胎的个数。
    复杂度分析:
    直接三个字符求解
    m * m * m 如果满数据就是n^6^,100^6^= 10^12^=1e12
    考虑所有的斜线,就是已知100以内互质对数 * n^2^
    100以内互质对数为6087,实际可能的是1547(优化过的)
    1547 * n * n = 1e7,当然还有常数,但是足够通过这个题目了

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=105;
    const int M=1e4+5;
    char s[N][N];
    int a[N<<1],b[N<<1],c[N<<1],d[N<<1];
    int ma[4][M<<1];
    vector<int> v[4];
    ll cal(int x) {
        if(x<3) return 0;
        return 1LL*x*(x-1)*(x-2)/6;
    }
    int main() {
        //freopen("in.txt","r",stdin);
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++) {
            scanf("%s",s[i]);
        }
        vector<pair<int,int> > vec;
        for(int i=0;i<n;i++) {
            for(int j=0;j<n;j++) {
                if(s[i][j]=='.') continue;
                //如果不是'.',a统计主对角线,b统计副对角线,c统计行,j统计列
                a[i-j+n]++,b[i+j]++,c[i]++,d[j]++;
                //记录当前点
                vec.push_back({i,j});
            }
        }
        ll ans=0;
        for(int i=0;i<n<<1;i++) {
            //对这四个进行统计
            ans+=cal(a[i])+cal(b[i])+cal(c[i])+cal(d[i]);
        }
        //循环剩下的需要格点
        for(int i=1;i<=n;i++) {
            for(int j=i+1;j<=n;j++) {
                if(__gcd(i,j)!=1) continue;
                //访问当前点
                for(int k=0;k<vec.size();k++) {
                    int x=vec[k].first,y=vec[k].second;
                    ma[0][x*i+y*j]++;ma[1][x*i-y*j+M]++;
                    ma[2][y*i+x*j]++,ma[3][y*i-x*j+M]++;
                    if(ma[0][x*i+y*j]==1) v[0].push_back(x*i+y*j);
                    if(ma[1][x*i-y*j+M]==1) v[1].push_back(x*i-y*j+M);
                    if(ma[2][y*i+x*j]==1) v[2].push_back(y*i+x*j);
                    if(ma[3][y*i-x*j+M]==1) v[3].push_back(y*i-x*j+M);
                }
                //四层为四个对应的方向
                for(int k=0;k<4;k++) {
                    for(int l=0;l<v[k].size();l++) {
                        ans+=cal(ma[k][v[k][l]]);
                        ma[k][v[k][l]]=0;
                    }
                    v[k].clear();
                }
            }
        }
        printf("%I64d
    ",ans);
        return 0;
    }
    

    出题人的代码
    预处理欧拉,枚举所有欧拉再枚举点,用的dp转移

    #include<bits/stdc++.h>
    using namespace std;
    
    vector<int>f[205];
    char G[105][105];
    int dp1[105][105],dp2[105][105];
    void PhiTable(int n){
        for(int i=2;i<=n;i++){
            for(int j=1;j<i;j++)
                if(__gcd(i,j)==1)
                    f[i].push_back(j);
        }
    }
    int main(){
        int n,sum=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%s",G[i]+1);
        int up=2*n-2;
        PhiTable(up);
        for(int k=1;k<=up;k++){
            if(k==1){
                //row and col
                for(int i=1;i<=n;i++)
                    for(int j=1;j<=n;j++){
                        if(dp1[i-1][j]>=2&&G[i][j]!='.')sum+=dp1[i-1][j]*(dp1[i-1][j]-1)/2;
                        dp1[i][j]=dp1[i-1][j]+(G[i][j]!='.');
                        if(dp2[i][j-1]>=2&&G[i][j]!='.')sum+=dp2[i][j-1]*(dp2[i][j-1]-1)/2;
                        dp2[i][j]=dp2[i][j-1]+(G[i][j]!='.');
                        //printf("i=%d j=%d 1 %d
    ",i,j,sum);
                    }
                continue;
            }
            for(int l=0;l<f[k].size();l++){
                for(int i=1;i<=n;i++)
                    for(int j=1;j<=n;j++)
                        dp1[i][j]=dp2[i][j]=(G[i][j]!='.');
                for(int i=1+f[k][l];i<=n;i++){
                    int x=i-f[k][l];
                    for(int j=1;j<=n-k+f[k][l];j++){
                        int y1=j+k-f[k][l];
                        if(dp1[x][y1]>=2&&G[i][j]!='.')sum+=dp1[x][y1]*(dp1[x][y1]-1)/2;
                        dp1[i][j]=dp1[x][y1]+(G[i][j]!='.');
                        //printf("upx=%d upy=%d dp1=%d 1(%d,%d) sum=%d
    ",x,y1,dp1[x][y1],i,j,sum);
                    }
                    for(int j=1+k-f[k][l];j<=n;j++){
                        int y2=j-k+f[k][l];
                        if(dp2[x][y2]>=2&&G[i][j]!='.')sum+=dp2[x][y2]*(dp2[x][y2]-1)/2;
                        dp2[i][j]=dp2[x][y2]+(G[i][j]!='.');
                        //printf("upx=%d upy=%d 2(%d,%d) sum=%d
    ",x,y2,i,j,sum);
                    }
                }
            }
        }
        printf("%d
    ",sum);
        return 0;
    }
    

    另一份验题代码

    #include <bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
    vector<pair<int, int>> V;
    int n, ans;
    string s[100];
    bool vis[100][100];
    inline int cal(int cnt)
    {
        return cnt >= 3 ? cnt * (cnt - 1) * (cnt - 2) / 6 : 0;
    }
    inline int add(int i, int j, int ai, int aj)
    {
        int cnt = 0;
        while (j < n&&i < n )
        {
            vis[i][j] = true;
            if (s[i][j] != '.')
                cnt++;
            i += ai, j += aj;
        }
        return cal(cnt);
    }
    inline int sub(int i, int j, int ai, int aj)
    {
        int cnt = 0;
        while (j >= 0&&i < n )
        {
            vis[i][j] = false;
            if (s[i][j] != '.')
                cnt++;
            i += ai, j -= aj;
        }
        return cal(cnt);
    }
    int main()
    {
    #ifdef bob
        freopen("data1.in", "r", stdin);
        int nol_cl = clock();
    #endif
        cin >> n;
        cin.get();
        for (int i = 0; i < n; i++)
            getline(cin, s[i]);
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                //min(n *1./ i, n*1. / j)为最多有几个点是优化
                if (__gcd(i, j) == 1 && min(n *1./ i, n*1. / j) > 2)
                {
                    V.push_back({i, j});
                }
            }
        }
        //cpp11写法,循环访问V
        for (auto X : V)
        {
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (!vis[i][j])
                    {
                        //左上到右下
                        ans += add(i, j, X.fi, X.se);
                    }
                }
            }
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (vis[i][j])
                    {
                        //左下到右上
                        ans += sub(i, j, X.fi, X.se);
                    }
                }
            }
        }
        //每一行
        for (int i = 0, j = 0; j < n; j++)
        {
            ans += add(i, j, 1, 0);
        }
        //每一列
        for (int i = 0, j = 0; i < n; i++)
        {
            ans += add(i, j, 0, 1);
        }
        cout << ans << "
    ";
    #ifdef bob
        LOG("Time: %dms
    ", int((clock() - nol_cl) / (double)CLOCKS_PER_SEC * 1000));
    #endif
        return 0;
    }
    

    2.6197: 最好一样

    这个是位运算的题目,这是“按位或”运算符,||是逻辑或,两个相应的二进制位中只要有一个为1,该位的结果值为1,即有1得1。曾经写过一个operator的理解,有兴趣可以看看。
    我们可以以当前数字作为下标进行统计个数。或会让这个数字变大(有些位上多1),所以我们从小的数字开始枚举,如果或的值不为i,说明异或的新值可以多a[i]个,当前清空,如果这个数字恰巧只有一个,那只能当读出现了,统计下来。
    update: 要么a[i]不或m,要么或m,如果存在显然或m,这样会减少。一个数字或上两次并不会变得更大,所以一次处理也可以。

    
    #include <bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    const int N=2e5+5;
    int a[N];
    int main()
    {
        int n,m,k,cnt=0;
        cin>>n>>m;    
        for(int i=1;i<=n;i++){
            cin>>k;
            //以数字作为下标进行统计
            a[k]++;
        }
        //从小到大开始枚举
        for(int i=1;i<=(1<<17);i++){
            if((i|m)!=i&&a[i]!=0){
                //肯定会进入到下个数
                a[i|m]+=a[i];
                a[i]=0;
            }
            if(a[i]==1) cnt++;
        }
        cout<<cnt<<endl;
    }
    
    

    mcj的代码

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int n,m,a[100005];
        int i;
        map<int,int> ma,mb;
        scanf("%d%d",&n,&m);
        for (i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            mb[a[i]]=a[i]|m;
            ma[mb[a[i]]]++;
        }
        int ans=0;
        for (i=0;i<n;i++)
        {
            if (ma[mb[a[i]]]==1)
                ans++;
        }
        printf("%d
    ",ans);
    }
    
    

    3.6198: Alice与进制转换进阶版

    非常抱歉这个题目出现了问题,影响了ydqdsg非常抱歉
    这个就是大数的一个题目,我们可以用大数进行模拟,当然下面的代码过不了终极版,你可以修改尝试下AC6222终极版

    #include <bits/stdc++.h>
    using namespace std;
    //最大为16进制转2进制,一位变四位
    const int N = 40005;
    string c = "0123456789ABCDEF";
    int ans[N];
    int main()
    {
        ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
        string s;
        int r1, r2;
        while (cin >> s >> r1 >> r2)
        {
            ans[0] = 0;
            int tot = 0;
            for (int i = 0, d; s[i]; i++)
            {
                if (s[i] == '-')
                {
                    cout << "-";
                    continue;
                }
                //s[i]对应为相应的数字
                if (s[i] >= '0' && s[i] <= '9')
                    d = s[i] - '0';
                else
                    d = s[i] - 'A' + 10;
                //ans是倒的,多了一位d,可能要进位,因为r1和r2的大小无法确定
                for (int j = 0; j <= tot; j++)
                {
                    //把ans[j]按照r1转换,因为多了1位,要再乘一次r1
                    d += ans[j] * r1;
                    //获取最新的ans[j]
                    ans[j] = d % r2;
                    //舍去当前位
                    d /= r2;
                }
                //d要新开才能存储下
                while (d)
                {
                    //高位会增加
                    ans[++tot] = d % r2;
                    d /= r2;
                }
            }
            for (int i = tot; i >= 0; i--)
                cout << c[ans[i]];
            cout << "
    ";
        }
    }
    

    Java写起来很容易

    import java.io.*;
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Scanner;
    import java.util.StringTokenizer;
    import java.io.IOException;
    import java.io.InputStream;
    
    public class Main {
    
        public static void main(String args[]) {
            Scanner sc = new Scanner(System.in);
            while(sc.hasNext()) {
                String s = sc.next();
                int r1 = sc.nextInt();
                int r2 = sc.nextInt();
                String a = new BigInteger(s,r1).toString(r2);
                System.out.println(a.toUpperCase());
            }
        }
    
    }
    
    

    4.6194: jump jump jump

    这个题目可以广搜解答,广搜可以保证每次搜到的都是最近的,且每个点只会被访问一次

    #include <bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    const int N = 1e5 + 5;
    vector<int> V[N];
    int ans[N];
    void bfs(int n)
    {
        queue<int> Q;
        Q.push(n);
        ans[n]=1;
        while (!Q.empty())
        {
            int t = Q.front();
            Q.pop();
            for (auto X : V[t])
            {
                //如果当前点可以被更新,即现在不是最小
                if (ans[X] > ans[t] + 1)
                {
                    ans[X] = ans[t] + 1;
                    Q.push(X);
                }
            }
        }
    }
    int main()
    {
        memset(ans, INF, sizeof(ans));
        int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1, x; i <= n; i++)
        {
            scanf("%d", &x);
            //没有到,建立一个边,代表一步可以从x+i跳回i
            if (x + i <= n)
                V[x + i].push_back(i);
        }
        bfs(n);
        int res = INF;
        for (int i = 1; i <= k; i++)
            res = min(res, ans[i]);
        if (res == INF)
            printf("-1
    ");
        else
            printf("%d
    ", res);
        return 0;
    }
    

    当然也可以记忆化搜索,这样用栈比较多,OJ的栈空间在这个题目够用

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=1e5+5;
    const int INF=0x3f3f3f3f;
    int a[N],f[N];
    int n,k;
    int dfs(int u) {
        //跳过了n或者当前跳0步,会死循环
        if(u>n||a[u]==0) return INF;
        //已经有答案了直接返回,就是在这里记忆化的
        if(f[u]!=INF) return f[u];
        return f[u]=dfs(u+a[u])+1;
    }
    int main() {
        //freopen("in.txt","r",stdin);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) {
            scanf("%d",&a[i]);
        }
        memset(f,INF,sizeof f);
        f[n]=0;
        int ans=INF;
        //对于前k个分别进行搜索
        for(int i=1;i<=k;i++) {
            ans=min(ans,dfs(i)+1);
        }
        printf("%d
    ",ans==INF?-1:ans);
        return 0;
    }
    

    当然也可以dp解答,因为每个点只访问一次,而且最小
    dp[i]代表i~n的最小步数

    #include <bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    const int N=1e5+5;
    int a[N],b[N];
    int main()
    {
        int n,m,k;
        cin>>n>>m;    
        for(int i=1;i<=n;i++) cin>>a[i];
        memset(b,INF,sizeof(b));
        b[n]=1; 
        for(int i=n;i>=1;i--){
            //可以到,需要更新答案
            if(i+a[i]<=n) b[i]=min(b[i+a[i]]+1,b[i]);
        }
        int minn=INF;
        for(int i=1;i<=m;i++) minn=min(minn,b[i]);
        if(minn>100000) cout<<"-1
    ";
        else cout<<minn<<endl;
        
    }
    

    5.6220: Alice与函数图像

    这个题目略微困难,y= - x³ - bx和 y = x³ + bx是等价的,因为他们的函数图像是对称的,x1³ + bx1 - x2³ + bx,有立方差公式(a-b)(a²+ab+b²)=a³-b³,以上进行合并为 ( X1 - X2 ) * ( X1 * X1 + X1 * X2 + X2 * X2 + b)
    update:感谢liqiyao0430hack了标程,时间仓促,出题人没有考虑到(写的不等式错了)。
    1.后面部分为1,假设(X1-X2)为素数P,后面为1,X1=P+X2
    代入得到3X2 * X2+3PX2 +P*P+b为二次函数,开口向上对称轴为-2/P,最低点为

    [(-frac{P}{2} ,frac{P^2}{4}+b) ]

    P=2且b=0,最小值为1,X1=1,X2=-1,所以这个需要特判掉。
    2.前面部分为1,X1-X2=1代入可得
    是对函数3 * i * i + 3 * i = p +1 -b存在解,当然也可以直接二分,也可以判断根。判断根会超过ll,需要unsiged,当然你也可以给他进行因式分解为3i * (i+1)= = p+1-b,这个不会爆ll,(p-1-c)%3 == 0 && int(sqrt((p-1-c)/3)) * (int(sqrt(p-1-c)/3))+1)==(p-1-c)/3

    二分代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    int c;
    bool la(LL x)
    {
        //后面部分是二次的,所以要1e9
        LL l=1,r=1e9+5;
        while(l<=r)
        {
            LL mi=(l+r)/2;
            LL y=mi-1;
            //存在值x
            if(mi*mi+y*y+mi*y+c==x)
            {
                return 1;
            }
            //递增函数,小于在右边
            else if(mi*mi+y*y+mi*y+c<x)
                l=mi+1;
            else r=mi-1;
        }
        return 0;
    }
    int main()
    {
        LL n;
        while(~scanf("%d%lld",&c,&n)){
            //特殊数据特判
            if(c==0&&n==2){
                printf("Existent
    ");
                continue;
            }
            printf("%s
    ",la(n)?"Existent":"Non-existent");
        }
        return 0;
    }
    

    判根的代码。由于sqrt在C++11以前是不精确的,而且unsinged会出问题,所以关闭了G++和C++的提交。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define LL unsigned long long
    int main(){
        LL p,b;
        while(cin>>b>>p){
            if(b==0&&p==2){
                printf("Existent
    ");
                continue;
            }
            //delta大于0才有解
            if(12*p-12*b-3>=0){
                LL sqr=sqrt(12*p-12*b-3);
                //必须解为整数,即能被整除
                if(sqr*sqr==12*p-12*b-3&&(3+sqr)%6==0)cout<<"Existent
    ";
                else cout<<"Non-existent
    ";
            }
            else cout<<"Non-existent
    ";
        }
        return 0;
    }
    

    6.6193: Alice玩16点

    我们可以对24点的代码进行改造,我们可以判断是是不是有4和9然后进行变换就可以了。
    当然也可以带上flag搜,dfs就是这样,暴力和好写的一个平衡。

    #include <bits/stdc++.h>
    using namespace std;
    int ff, fff, a[4], aa[4], b[255];
    char str[15];
    //处理10和大小王
    int la()
    {
        if (strlen(str) > 2)
            return 0;
        if (strlen(str) == 2)
            return 10;
        return b[str[0]];
    }
    void dfs(int sum, int f, int m)
    {
        //找到了,不在进行多余的搜索
        if (ff)
            return;
        if (m == 2)
        {
            //搜索结束,看看是否存在16
            if (sum + f == 16 || sum - f == 16 || sum * f == 16 || f && sum / f == 16)
                ff = 1;
            return;
        }
        //不加括号
        dfs(sum + f, a[m + 1], m + 1), dfs(sum - f, a[m + 1], m + 1), dfs(sum * f, a[m + 1], m + 1);
        //不能除0
        if (f)
            dfs(sum / f, a[m + 1], m + 1);
        //括号加在后面
        dfs(sum, f + a[m + 1], m + 1), dfs(sum, f - a[m + 1], m + 1), dfs(sum, f * a[m + 1], m + 1);
        //不能除0
        if (a[m + 1])
            dfs(sum, f / a[m + 1], m + 1);
    }
    int main()
    {
        //分别进行映射
        b['A'] = 1, b['J'] = 11, b['Q'] = 12, b['K'] = 13;
        for (int i = '2'; i <= '9'; i++)
            b[i] = i - '0';
        int T;
        scanf("%d", &T);
        while (T--)
        {
            for (int i = 0; i < 3; i++)
                scanf("%s", str), aa[i] = la();
            //排序之后得到去全排列
            sort(aa, aa + 3);
            ff = 0;
            do
            {
                for (int j = 0; j < 3; j++)
                    a[j] = aa[j];
                dfs(a[0], a[1], 1);
                //特殊处理可以使用开根
                for (int i = 0; i < 3; i++)
                {
                    int x = sqrt(aa[i] + 0.5);
                    if (x > 1 && x * x == aa[i])
                    {
                        for (int j = 0; j < 3; j++)
                            a[j] = aa[j];
                        a[i] = x;
                        dfs(a[0], a[1], 1);
                    }
                }
            } while (next_permutation(aa, aa + 3) && !ff);
            printf("%s
    ", ff ? "YES" : "NO");
        }
        return 0;
    }
    

    但是三个数其实枚举实现起来更简单。我们需要考虑的是括号的位置。

    #include <bits/stdc++.h>
    using namespace std;
    int a[4], aa[4], b[255];
    char str[5];
    int la()
    {
        if (strlen(str) > 2)
            return 0;
        if (strlen(str) == 2)
            return 10;
        return b[str[0]];
    }
    int cal(int a, int b, int index)
    {
        if (index == 0)
            return a + b;
        if (index == 1)
            return a - b;
        if (index == 2)
            return a * b;
        if (b == 0)
            return 0x3f3f3f3f;
        return a / b;
    }
    int Ans()
    {
        //封装为函数
        do
        {
            //枚举符号
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    //括号放在那里都一样
                    int res = cal(cal(aa[0], aa[1], i), aa[2], j);
                    if (res == 16 || res == -16)
                    {
                        return 1;
                    }
                    for (int k = 0; k < 3; k++)
                    {
                        int x = sqrt(aa[k] + 0.5);
                        if (x > 1 && x * x == aa[k])
                        {
                            for (int l = 0; l < 3; l++)
                                a[l] = aa[l];
                            a[k] = x;
                            res = cal(cal(a[0], a[1], i), a[2], j);
                            if (res == 16 || res == -16)
                            {
                                return 1;
                            }
                        }
                    }
                }
            }
        } while (next_permutation(aa, aa + 3));
        return 0;
    }
    int main()
    {
        b['A'] = 1, b['J'] = 11, b['Q'] = 12, b['K'] = 13;
        for (int i = '2'; i <= '9'; i++)
            b[i] = i - '0';
        int T;
        scanf("%d", &T);
        while (T--)
        {
            for (int i = 0; i < 3; i++)
                scanf("%s", str), aa[i] = la();
            sort(aa, aa + 3);
            printf("%s
    ", Ans() ? "YES" : "NO");
        }
        return 0;
    }
    

    带上flag进行深搜

    #include <bits/stdc++.h>
    using namespace std;
    int a[5];
    int f;
    void dfs(int pos,int flag,int sum)
    {
        if(pos==4){
            if(sum==16) f=1;
            return;
        }
        if(pos==1){
            if(a[pos]==4||a[pos]==9) dfs(pos+1,0,sqrt(a[pos]));
            dfs(pos+1,1,a[pos]);
        }
        else{
            if((a[pos]==4||a[pos]==9)&&flag==1){
                dfs(pos+1,0,sum*sqrt(a[pos]));
                dfs(pos+1,0,sum/sqrt(a[pos]));
                dfs(pos+1,0,sum+sqrt(a[pos]));
                dfs(pos+1,0,sum-sqrt(a[pos]));
            }
            dfs(pos+1,flag,sum*a[pos]);
            if(a[pos]!=0)
            dfs(pos+1,flag,sum/a[pos]);
            dfs(pos+1,flag,sum+a[pos]);
            dfs(pos+1,flag,sum-a[pos]);
        }
        
    }
    int main()
    {
        int T,n,k;
        cin>>T;
        while(T--){
            f=0;
            string s;
            for(int i=1;i<=3;i++){
                cin>>s;
                if(s[0]>='2'&&s[0]<='9') a[i]=s[0]-'0';
                else if(s[0]=='A') a[i]=1;
                else if(s[0]=='1') a[i]=10;
                else if(s[0]=='Q') a[i]=12;
                else if(s[0]=='K') a[i]=13;
                else if(s[0]=='J'&&s.size()==1) a[i]=11;
                else a[i]=0;
            }
            sort(a+1,a+4);
            do{
                dfs(1,1,0);
            }while(next_permutation(a+1,a+4)); 
            if(f==1) cout<<"YES
    ";
            else cout<<"NO
    ";
        }
    }
    

    7.6202: 有趣的活动

    排成圈,其实就是扩展一次。所以可以边扩展边记录,找到最大值即可。
    这个题目很多人被卡超时,如果使用C++请关闭输入输出同步,尽量使用scanf和printf。不要混用。如果使用JAVA你可以去codeforces看下peter的代码,把它的Java读入抄下来。
    关闭同步代码:ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    这个自己也可以百度,也是考点,如果还不能通过就要考虑使用快读

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=5e4+5;
    double a[N+N];
    int f[N+N];
    int main() {
        int T,n;
        scanf("%d",&T);
        while(T--) {
            scanf("%d",&n);
            for(int i=0;i<n;i++) {
                scanf("%lf",&a[i]);
                a[i+n]=a[i];
            }
            f[0]=1;
            for(int i=1;i<n<<1;i++) {
                //大于等于前一个,当前+1,否则从1开始喊
                if(a[i]<=a[i-1]) f[i]=f[i-1]+1;
                else f[i]=1;
            }
            //遍历寻找,但是最大为n
            int ans=0;
            for(int i=0;i<n+n;i++) {
                ans=max(ans,min(f[i],n));
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    8.6196: Alice玩五子棋

    这个题目可以循环判断,也可以直接搜索
    搜索写起来更简单些,当然套套也就是1001的一部分

    #include<bits/stdc++.h>
    using namespace std;
    
    char G[20][20];
    int flag;
    int dx[]={0,0,1,-1,-1,-1,1,1};
    int dy[]={1,-1,0,0,-1,1,-1,1};
    void check(int x,int y){
        for(int dir=0;dir<8;dir++){
            int f=1;
            //四个方向
            for(int i=1;i<=4;i++){
                int vx=x+dx[dir]*i,vy=y+dy[dir]*i;
                //越界或者不是
                if(vx<1||vx>15||vy<1||vy>15||G[vx][vy]!=G[x][y]){
                    f=0;break;
                }
            }
            if(f)flag=(G[x][y]=='O'?1:2);
        }
    }
    int main(){
        while(scanf("%s",G[1]+1)!=EOF){
            for(int i=2;i<=15;i++)scanf("%s",G[i]+1);
            flag=0;
            for(int i=1;i<=15;i++)
                for(int j=1;j<=15;j++){
                    if(G[i][j]=='.')continue;
                    check(i,j);
                }
            if(flag==0)printf("continue
    ");
            else if(flag==1)printf("Alice Wins!
    ");
            else printf("Bob Wins!
    ");
        }
        return 0;
    }
    

    复用1001

    #include <bits/stdc++.h>
    using namespace std;
    string s[15];
    int n = 15;
    int add(int i, int j, int ai, int aj, char c)
    {
        int cnt = 0;
        while (i < n && j < n)
        {
            if (s[i][j] == c)
            {
                cnt++;
                if (cnt >= 5)
                    return 1;
            }
            else
                cnt = 0;
            i += ai, j += aj;
        }
        return 0;
    }
    int sub(int i, int j, int ai, int aj, char c)
    {
        int cnt = 0;
        while (i >=0 && j <n)
        {
            if (s[i][j] == c)
            {
                cnt++;
                if (cnt >= 5)
                    return 1;
            }
            else
                cnt = 0;
            i -= ai, j += aj;
        }
        return 0;
    }
    int la(char c)
    {
        for (int i = 0, j = 0; j < n; j++)
            if (add(i, j, 1, 0, c))
                return 1;
        for (int i = 0, j = 0; i < n; i++)
            if (add(i, j, 0, 1, c))
                return 1;
        //第一行add
        for (int i = 0, j = 0; j < n; j++)
            if (add(i, j, 1, 1, c))
                return 1;
        //第一列add
        for (int i = 1, j = 0; i < n; i++)
            if (add(i, j, 1, 1, c))
                return 1;
        //最后一行sub
        for (int i = n - 1, j = 1; j < n; j++)
            if (sub(i, j, 1, 1, c))
                return 1;
        //第一列sub
        for (int i = 1, j = 0; i < n; i++)
            if (sub(i, j, 1, 1, c))
                return 1;
        return 0;
    }
    int main()
    {
        while (cin >> s[0])
        {
            for (int i = 1; i < n; i++)
                cin >> s[i];
            if (la('X'))
                cout << "Bob Wins!
    ";
            else if (la('O'))
                cout << "Alice Wins!
    ";
            else
                cout << "continue
    ";
        }
    }
    

    循环的代码,要保证复制粘贴不能出问题。

    #include<bits/stdc++.h>
    using namespace std;
    string s[15];
    int n=15;
    int la(char c)
    {
        for(int i=0;i<=n-5;i++)
        {
            for(int j=0;j<=n-5;j++)
            {
                if(s[i][j]==c&&s[i][j]==s[i+1][j+1]&&s[i][j]==s[i+2][j+2]&&s[i][j]==s[i+3][j+3]&&s[i][j]==s[i+4][j+4]
                ||s[i][n-j-1]==c
                &&s[i][n-j-1]==s[i+1][n-j-2]&&s[i][n-j-1]==s[i+2][n-j-3]&&s[i][n-j-1]==s[i+3][n-j-4]&&s[i][n-j-1]==s[i+4][n-j-5]
                )
                    return 1;
            }
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<=n-5;j++)
            {
                if(s[i][j]==c&&s[i][j]==s[i][j+1]&&s[i][j]==s[i][j+2]&&s[i][j]==s[i][j+3]&&s[i][j]==s[i][j+4])
                return 1;
            }
        }
        for(int i=0;i<=n-5;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(s[i][j]==c&&s[i][j]==s[i+1][j]&&s[i][j]==s[i+2][j]&&s[i][j]==s[i+3][j]&&s[i][j]==s[i+4][j])
                return 1;
            }
        }
        return 0;
    }
    int main()
    {
        while(cin>>s[0])
        {
            for(int i=1;i<n;i++)
            cin>>s[i];
            if(la('X'))
            cout<<"Bob Wins!
    ";
            else if(la('O'))
            cout<<"Alice Wins!
    ";
            else cout<<"continue
    ";
        }
    }
    

    9.6221: taozi与一元一次方程

    这个就是方程的判断,y=ax+b,斜率为无穷对应无数个解,如果a=0,且y!=b是无解

    #include<bits/stdc++.h>
    using namespace std;
    
    int main(){
        int y,a,b;
        while(scanf("%d%d%d",&y,&a,&b)!=EOF){
            if(a==0){
                if(y==b)printf("Infinite
    ");
                else printf("Unsolvable
    ");
            }else{
                printf("%.2f
    ",(y-b)*1./a);
            }
        }
        return 0;
    }
    

    10.6191: Alice与分数序列

    直接相除比较,但是要进行强制转换。
    除法转乘法,注意超过了int,int最大值2e9左右。

    #include <bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        int a,b,c,d;
        while(cin>>a>>b>>c>>d)
        {
            if(a*1.0/b>c*1.0/d)
            {
                cout<<a<<" / "<<b<<" > "<<c<<" / "<<d<<"
    ";
            }
            else if(a*1.0/b<c*1.0/d)
            {
                cout<<a<<" / "<<b<<" < "<<c<<" / "<<d<<"
    ";
            }
            else
            {
                cout<<a<<" / "<<b<<" = "<<c<<" / "<<d<<"
    ";
            }
        }
    }
    

    long long转乘法

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    int main(){
        LL a,b,c,d;
        while(scanf("%lld%lld%lld%lld",&a,&b,&c,&d)!=EOF){
            LL x1=a*d,x2=b*c;
            printf("%lld / %lld ",a,b);
            if(x1==x2)printf("=");
            else if(x1>x2)printf(">");
            else printf("<");
            printf(" %lld / %lld
    ",c,d);
        }
        return 0; 
    }
    

    当然你不用输出长整型,乘上1LL可以转类型,我们仅仅比较的时候需要

    #include <bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        int a,b,c,d;
        while(cin>>a>>b>>c>>d)
        {
            if(a*1LL*d>c*1LL*b)
            {
                cout<<a<<" / "<<b<<" > "<<c<<" / "<<d<<"
    ";
            }
            else if(a*1LL*d<c*1LL*b)
            {
                cout<<a<<" / "<<b<<" < "<<c<<" / "<<d<<"
    ";
            }
            else
            {
                cout<<a<<" / "<<b<<" = "<<c<<" / "<<d<<"
    ";
            }
        }
    }
    

    11.6203: Alice与三角形面积

    可以直接勾股定理,也可以相似(两小三角形相似),而且怎么AC都能对。勾股数恰好满足可以凑答案,甚至正好整除。
    这个题错误的是因为多组数据。

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        int a,b,c;
        while(~scanf("%d%d%d",&a,&b,&c)) {
            printf("%.3f
    ",sqrt(b*b+c*c)*a/2);
        }
        return 0;
    }
    

    相似

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        int a,b,c;
        while(~scanf("%d%d%d",&a,&b,&c)) {
            printf("%.3f
    ",a*(b*a/c)/2.0);
        }
        return 0;
    }
    
  • 相关阅读:
    [转载]Bison-Flex 笔记
    LeetCode 5 Longest Palindromic Substring manacher算法,最长回文子序列,string.substr(start,len) 难度:2
    LeetCode 6 ZigZag Conversion 模拟 难度:0
    LeetCode 7 Reverse Integer int:2147483647-2147483648 难度:2
    #Leetcode# 383. Ransom Note
    #Leetcode# 92. Reverse Linked List II
    #Leetcode# 143. Reorder List
    #Leetcode# 532. K-diff Pairs in an Array
    #Leetcode# 86. Partition List
    Sudoku
  • 原文地址:https://www.cnblogs.com/BobHuang/p/12610795.html
Copyright © 2020-2023  润新知