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 如果滿數據就是n6,1006= 1012=1e12
考慮所有的斜線,就是已知100以內互質對數 * n2
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\n",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\n",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\n",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\n",x,y2,i,j,sum);
                }
            }
        }
    }
    printf("%d\n",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 << "\n";
#ifdef bob
    LOG("Time: %dms\n", 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\n",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 << "\n";
    }
}

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\n");
    else
        printf("%d\n", 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\n",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\n";
    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\n");
            continue;
        }
        printf("%s\n",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\n");
            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\n";
            else cout<<"Non-existent\n";
        }
        else cout<<"Non-existent\n";
    }
    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\n", 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\n", 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\n";
        else cout<<"NO\n";
    }
}

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\n",ans);
    }
    return 0;
}

8.6196: Alice玩五子棋

循環+函數,法力無邊

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


循環的代碼,要保證復制粘貼不能出問題。

#include <bits/stdc++.h>
using namespace std;
char s[15][16];
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])
                return 1;
            if(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;
}
void WhoWins()
{
    if (la('X'))
        cout << "Bob Wins!\n";
    if (la('O'))
        cout << "Alice Wins!\n";
    cout << "continue\n";
}
int main()
{
    while (cin >> s[0])
    {
        for (int i = 1; i < n; i++)
            cin >> s[i];
        WhoWins();
    }
}

這個題目可以循環判斷,也可以直接搜索
搜索寫起來更簡單些,當然套套也就是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\n");
        else if(flag==1)printf("Alice Wins!\n");
        else printf("Bob Wins!\n");
    }
    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!\n";
        else if (la('O'))
            cout << "Alice Wins!\n";
        else
            cout << "continue\n";
    }
}

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\n");
            else printf("Unsolvable\n");
        }else{
            printf("%.2f\n",(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<<"\n";
        }
        else if(a*1.0/b<c*1.0/d)
        {
            cout<<a<<" / "<<b<<" < "<<c<<" / "<<d<<"\n";
        }
        else
        {
            cout<<a<<" / "<<b<<" = "<<c<<" / "<<d<<"\n";
        }
    }
}

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\n",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<<"\n";
        }
        else if(a*1LL*d<c*1LL*b)
        {
            cout<<a<<" / "<<b<<" < "<<c<<" / "<<d<<"\n";
        }
        else
        {
            cout<<a<<" / "<<b<<" = "<<c<<" / "<<d<<"\n";
        }
    }
}

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\n",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\n",a*(b*a/c)/2.0);
    }
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM