2023 CCPC河南省賽題解11/12

https://codeforces.com/gym/104354

 A

注意到a串最大長度也就26,所以可以枚舉a串,判斷剩下的串是不是迴文的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read()
{
    ll x;scanf("%lld",&x);return x;
}
char s[100010];
int f[300],n;
int check(int l,int r)
{
    while(l<r)
    {
        if(s[l]!=s[r])
            return 0;
        l++;
        r--;
    }
    return 1;
}
void work()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i='a';i<='z';i++)
        f[i]=0;
    for(int i=1;i<n;i++)
    {
        if(f[s[i]])
            break;
        f[s[i]]=1;
        if(check(i+1,n))
        {
            printf("HE\n");
            return ;
        }
    }
    printf("NaN\n");
}
int main()
{
    // freopen("1.in","r",stdin);
    for(int t=read();t;t--)
        work();
}
A

B

考慮如果有ai>aj,i<j,那麼i和j必須在同一個塊裏。否則隨便劃分。

所以貪心地劃分成最小的不可再分的幾個區間。從l到i,i是右端點當且僅當區間最大值小於等於後面的最小值。

把這些右端點標記一下,滿足答案的k必須滿足k、2k、3k、4k...都被標記。

預處理後綴最小值,再暴力判斷一下合法的k,複雜度nlogn。

int n,a[1000010],m[1000010],f[1000010],ans;
int main()
{
    // freopen("1.in","r",stdin);
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    m[n+1]=a[n];
    for(int i=n;i>=1;i--)
        m[i]=min(m[i+1],a[i]);
    int maxx=0;
    for(int i=1;i<=n;i++)
    {
        maxx=max(maxx,a[i]);
        if(maxx<=m[i+1]||i==n)
        {
            f[i]=1;
            maxx=0;
        }
    }
    for(int k=1;k<=n;k++)
    {
        ans++;
        for(int i=k;i<=n;i+=k)
            if(f[i]==0)
            {
                ans--;
                break;
            }
    }
    printf("%d",ans);
}
B

C

先跑一個kmp。

因爲前100個和中間某一段相同的概率很小,所以kmp一但發現f[i]大於等於100就認爲不是隨機數即可。

int n,f[1000010];
char s[1000010];
int main()
{
    // freopen("1.in","r",stdin);
    scanf("%s",s);
    n=strlen(s);
    for(int i=1;i<n;i++)
    {
        int j=f[i-1];
        while(j>0&&s[i]!=s[j])
            j=f[j-1];
        if(s[i]==s[j])
            j++;
        f[i]=j;
        if(f[i]>=100)
        {
            printf("No");
            return 0;
        }
    }
    printf("Yes");
}
C

D

首先來點特例:

n=1或者顏色大於邊數的話輸出1 1。把沒有連邊的點刪了,刪了不會影響答案。刪了若干個點之後發現某個點沒有連邊了,那麼也需要刪掉。可以用dfs來做這個過程。如果剩下沒點了也可以輸出11。

那麼帶着非孤立點和有用的邊繼續出發。

考慮做n輪刪邊操作:先用當前的邊跑並查集。然後對於每條邊,如果相連的點的歸屬情況不同,就可以把這個邊刪了。

刪了這麼多邊後,就只剩下有用的邊,並且所有的點所屬並查集情況相同。找一找最大的並查集大小並輸出即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read() {
    ll x;
    scanf("%lld",&x);
    return x;
}
#define M 2000010
#define N 501
struct edge {
    int x,y,v;
    friend bool operator <(edge x,edge y) {
        return x.v<y.v;
    }
} e[M];
int n,m,in[N],sum[N],minf[N],maxf[N];
vector<short>f[N];
int k;
vector<pair<int,int>>ee[N];
int checkin(int x) {
    for(int i=1; i<=k; i++)
        if(f[x][i]==0)
            return 0;
    return 1;
}
void dfs(int x) {
    in[x]=0;
    for(auto y:ee[x]) {
        if(in[y.first]==0)continue;
        f[y.first][y.second]--;
        if(f[y.first][y.second]==0)
            sum[y.first]--;
        if(sum[y.first]==0)
            dfs(y.first);
    }
}
int getfa(int x,int v) {
    return f[x][v]==x?x:f[x][v]=getfa(f[x][v],v);
}
void merge(int v,int x,int y) {
    x=getfa(x,v);
    y=getfa(y,v);
    if(x==y)return ;
    if(x>y)swap(x,y);
    if(v==1)
        sum[y]+=sum[x];
    f[x][v]=y;
}
vector<int>num,t[N];
vector<int>resn;
void sortn() {
    num.clear();
    for(auto i:resn)
        num.push_back(i);
    for(int i=1; i<=k; i++) {
        for(auto x:resn)
            t[x].clear();
        for(auto x:num) {
            t[getfa(x,i)].push_back(x);
        }
        num.clear();
        for(auto i:resn)
            for(auto x:t[i])
                num.push_back(x);
    }
}
int check() {
    for(auto i:resn)
    {
        minf[i]=maxf[i]=getfa(i,1);
        for(int j=1; j<=k; j++)
        {
            
            minf[i]=min(minf[i],(int)f[i][j]);
            maxf[i]=max(maxf[i],(int)f[i][j]);
        }

    }
    for(auto i:resn)
        for(int j=1; j<=k; j++)
            if(f[i][j]!=f[i][1])
                return 0;
    return 1;
}
void work() {
    k=read();
    n=read();
    m=read();
    resn.clear();
    for(int i=1; i<=n; i++)
        ee[i].clear();
    for(int i=1; i<=m; i++) {
        e[i].v=read();
        e[i].x=read();
        e[i].y=read();
        ee[e[i].x].push_back({e[i].y,e[i].v});
        ee[e[i].y].push_back({e[i].x,e[i].v});
    }
    if(n==1||k>m) {
        printf("1\n1\n");
        return ;
    }
    for(int i=1; i<=n; i++)
        f[i].resize(m+1);
    for(int i=1; i<=n; i++) {
        in[i]=1;
        for(int j=1; j<=m; j++)
            f[i][j]=0;
    }
    for(int i=1; i<=m; i++) {
        if(f[e[i].x][e[i].v]==0)
            sum[e[i].x]++;
        if(f[e[i].y][e[i].v]==0)
            sum[e[i].y]++;
        f[e[i].x][e[i].v]++;
        f[e[i].y][e[i].v]++;
    }
    for(int i=1; i<=n; i++) {
        if(in[i]&&checkin(i)==0) {
            dfs(i);
        }
        if(in[i])
            resn.push_back(i);
    }
    if(resn.size()==0)
    {
        printf("1\n1\n");
        return ;
    }
    int t=0;
    for(int i=1; i<=m; i++) {
        if(in[e[i].x]==0||in[e[i].y]==0)
            continue;
        t++;
        e[t]=e[i];
    }
    m=t;
    for(int jj=1;jj<=resn.size();jj++)
    {
        for(auto i:resn) {
            for(int j=1; j<=k; j++) {
                f[i][j]=i;
            }
            sum[i]=1;
        }
        for(int i=1; i<=m; i++) {
            merge(e[i].v,e[i].x,e[i].y);
        }
        sortn();
        if(check()) {
            break;
        }
        int t=0;
        for(int i=1; i<=m; i++) 
        {
            if(minf[e[i].x]==minf[e[i].y]&&maxf[e[i].x]==maxf[e[i].y])
            {
                t++;
                e[t]=e[i];
            }
        }
        m=t;
    }
    int ans=resn[0];
    for(auto i:resn)
        if(sum[getfa(i,1)]>sum[f[ans][1]])
            ans=i;
    printf("%d\n",sum[f[ans][1]]);
    for(auto i:resn)
        if(f[ans][1]==getfa(i,1))
            printf("%d ",i);
    printf("\n");
}
int main() {
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    for(int t=read(); t; t--)
        work();
}
D

 E

dp一下

基本轉移方式是從f[i-1][j][k]和f[i][j-1][k]轉移過來,如果是1可以+1,否則不能加

高級的轉移是如果當前是問號,可以從f[i-1][j][k-1]和f[i][j-1][k-1]轉移過來並加一。如果k=0就不能有這個轉移。

空間開不下,所以壓縮一下。

int n,m,x,f[2][510][1010];
char s[510][510];
void work()
{
    n=read();m=read();x=read();
    for(int i=1;i<=n;i++)
        scanf("%s",s[i]+1);
    for(int i=0;i<=m;i++)
        for(int j=0;j<=x;j++)
            f[0][i][j]=f[1][i][j]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(s[i][j]=='1')
                f[i&1][j][0]=max(f[i&1][j-1][0],f[(i-1)&1][j][0])+1;
            else
                f[i&1][j][0]=max(f[i&1][j-1][0],f[(i-1)&1][j][0]);
            for(int k=1;k<=x;k++)
            {
                if(s[i][j]=='1')
                    f[i&1][j][k]=max(f[i&1][j-1][k],f[(i-1)&1][j][k])+1;
                else
                    f[i&1][j][k]=max(f[i&1][j-1][k],f[(i-1)&1][j][k]);
                if(s[i][j]=='?')
                    f[i&1][j][k]=max(f[i&1][j][k], max(f[i&1][j-1][k-1],f[(i-1)&1][j][k-1])+1);
            }
        }
    }
    int ans=f[n&1][m][0];
    for(int i=1;i<=x;i++)
        ans=max(ans,f[n&1][m][i]);
    printf("%d\n",ans);
}
int main()
{
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    for(int t=read();t;t--)
        work();
}
E

F

sort一下,然後枚舉所有長爲k的子串。

min(|a[i]-a[j]|)是所有相鄰數字的差的最小值,用multiset維護一下。max(|a[i]-a[j]|)顯然是子串的左右兩端。

ll n,k,a[500010],ans;
multiset<ll>o;
int main()
{
    n=read();k=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    sort(a+1,a+1+n);
    for(int i=1;i<k;i++)
        o.insert(a[i+1]-a[i]);
    ans=*o.begin()*(a[k]-a[1]);
    for(int i=k;i<=n;i++)
    {
        ans=min(ans,*o.begin()*(a[i]-a[i-k+1]));
        o.erase(o.find(a[i-k+2]-a[i-k+1]));
        o.insert(a[i+1]-a[i]);
    }
    printf("%lld",ans);
}
F

 

G

大膽模擬

判斷INF我剛開始用了log10,wa了,就換了用1e18除x的方式,穩定不出錯。

害怕substr慢就用模擬的方式寫了寫。本來ans[i]+=substr就很好寫的。

以及賽時我只能用pta。如果給我dev的話處理數據本來很快的。

鄭輕罪大惡極

char a[][100]={"",
".................................................................................",
".................................................................................",
".0000000.......1.2222222.3333333.4.....4.5555555.6666666.7777777.8888888.9999999.",
".0.....0.......1.......2.......3.4.....4.5.......6.............7.8.....8.9.....9.",
".0.....0.......1.......2.......3.4.....4.5.......6.............7.8.....8.9.....9.",
".0.....0.......1.2222222.3333333.4444444.5555555.6666666.......7.8888888.9999999.",
".0.....0.......1.2.............3.......4.......5.6.....6.......7.8.....8.......9.",
".0.....0.......1.2.............3.......4.......5.6.....6.......7.8.....8.......9.",
".0000000.......1.2222222.3333333.......4.5555555.6666666.......7.8888888.9999999.",
".................................................................................",
};
char b[100][100]={"",
".............................................................",
".00000.....1.22222.33333.4...4.55555.66666.77777.88888.99999.",
".0...0.....1.....2.....3.4...4.5.....6.........7.8...8.9...9.",
".0...0.....1.22222.33333.44444.55555.66666.....7.88888.99999.",
".0...0.....1.2.........3.....4.....5.6...6.....7.8...8.....9.",
".00000.....1.22222.33333.....4.55555.66666.....7.88888.99999.",
".............................................................",
".............................................................",
".............................................................",
".............................................................",
};
char c[100][100]={"",
".................................",
".................................",
".........IIIIIII.N.....N.FFFFFFF.",
"............I....NN....N.F.......",
".=======....I....N.N...N.F.......",
"............I....N..N..N.FFFFFFF.",
".=======....I....N...N.N.F.......",
"............I....N....NN.F.......",
".........IIIIIII.N.....N.F.......",
".................................",
};
char ans[20][1000];
int tot;
void add(ll x,int d)
{
    stack<int>q;
    while(x)
    {
        q.push(x%10);
        x=x/10;
    }
    while(q.size())
    {
        for(int i=1;i<=10;i++)
        {
            if(d==1)
                for(int j=tot,k=q.top()*8;j<tot+8;j++,k++)
                    ans[i][j]=a[i][k];
            else
                for(int j=tot,k=q.top()*6;j<tot+6;j++,k++)
                    ans[i][j]=b[i][k];
        }
        if(d==1)
            tot+=8;
        else
            tot+=6;
        q.pop();
    }
}
void INV(int l,int r)
{
    for(int i=1;i<=10;i++)
        for(int j=tot,tl=l;tl<=r;j++,tl++)
            ans[i][j]=c[i][tl];
    tot=tot+r-l+1;
}
int check(ll x,ll y)
{
    if(x==1)
        return 0;
    ll a=1e18;
    for(int i=1;i<=y;i++)
    {
        if(a<x)
            return 1;
        a=a/x;
    }
    return 0;
}
ll quick(ll x,ll y)
{
    if(x==1)
        return 1;
    ll t=1;
    for(;y;y--)
        t=t*x;
    return t;
}
void work()
{
    ll x,y;
    scanf("%lld^{%lld}",&x,&y);
    tot=0;
    add(x,1);
    add(y,2);
    INV(0,7);
    if(check(x,y))
        INV(8,31);
    else
        add(quick(x,y),1);
    for(int i=1;i<=10;i++)
    {
        ans[i][tot]=0;
        printf("%s.\n",ans[i]);
    }
    printf("\n");
}
int main()
{
    // freopen("1.out","w",stdout);
    for(int t=read();t;t--)
        work();
}
G

H

把玩一下推式子即可。再和記得給下界0取max,給上界n*2取min。

int n,k;
void work()
{
    n=read();k=read();
    printf("%d %d\n",max(0,n-(k-1)/2),min(n*2,n+k/2));
}
int main()
{
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    for(int t=read();t;t--)
        work();
}
H

I

求交點數量。問題轉化成對於每個豎線起點給x++終點給x--,對於每個橫線問區間y1y2裏現在有幾個x即可。

int c[200010],n,jia[200010][2],jian[200010][2],l[200010],r[200010];
ll ans;
int lowbit(int x)
{
    return x&(-x);
}
int ask(int d)
{
    int sum=0;
    while(d)
    {
        sum=sum+c[d];
        d=d-lowbit(d);
    }
    return sum;
}
void add(int d,int v)
{
    while(d<=n)
    {
        c[d]+=v;
        d=d+lowbit(d);
    }
}
int main()
{
    // freopen("1.in","r",stdin);
    n=read();
    ans=4ll*n*n;
    int X1,X2,Y1,Y2;
    for(int i=1;i<=n;i++)
    {
        X1=read();Y1=read();
        X2=read();Y2=read();
        jia[Y1][0]=X1;
        jia[Y1][1]=X2;
        jian[Y2][0]=X1;
        jian[Y2][1]=X2;
        l[Y1]=X1;
        r[Y1]=X2;
        l[Y2]=X1;
        r[Y2]=X2;
        ans-=X2*2-X1*2+Y2*2-Y1*2;
    }
    n=n*2;
    for(int i=1;i<=n;i++)
    {
        if(jian[i][0])
        {
            add(jian[i][0],-1);
            add(jian[i][1],-1);
        }
        ans+=(ask(r[i])-ask(l[i]-1));
        if(jia[i][0])
        {
            add(jia[i][0],1);
            add(jia[i][1],1);
        }
    }
    cout<<ans;
}
I

J

初中數學。初中數學好並且acos用的熟練即可。不知道爲什麼賽時沒人寫(以及我上機最後半小時很急沒調出來)

struct node
{
    ll x,y;
    void in()
    {
        x=read();
        y=read();
    }
}p,a,b;
ll r;
double ap,ad,d;
double askd(node x,node y)
{
    return sqrt( (x.x-y.x)*(x.x-y.x)+ (x.y-y.y)*(x.y-y.y));
}
ll askdd(node x,node y)
{
    return (x.x-y.x)*(x.x-y.x)+ (x.y-y.y)*(x.y-y.y);
}
void work()
{
    p.in();
    a.in();
    b.in();
    r=read()*read();
    ap=askd(a,p);
    ad=askd(a,b)/2;
    d=sqrt(ap*ap-ad*ad);
    if(askdd(a,p)<=r*r)
    {
        printf("%.12lf\n",acos(-1)*r*r);
    }
    else if(d<=r)
    {
        printf("%.12lf\n",r*sqrt(ap*ap-r*r)*2+ (acos(-1)-acos(r/ap)*2)*r*r);
    }
    else
    {
        double t=sqrt(ap*ap-r*r);
        printf("%.12lf\n",d*ad+r*t+(acos(-1)-acos(d/ap)-acos(r/ap))*r*r);
    }
}
int main()
{
    // freopen("1.in","r",stdin);
    for(int t=read();t;t--)
        work();
}
J

 K

唉賽時卡了半天。現在想想主要是hs證明了不能只用2和3,然後就誤入歧途了。

void work(int n){
    if(n<=4)
        printf("-1\n");
    else if(n==5)
        printf("4 1 3 5 2\n");
    else if(n==6)
        printf("1 3 5 2 4 6\n");
    else if(n==7)
        printf("1 3 5 2 7 4 6\n");
    else if(n==8)
        printf("1 6 3 8 5 2 7 4\n");
    else if(n==11)
        printf("1 3 10 5 2 7 9 11 8 6 4\n");
    else
    {
        for(int i=1;i+2<=n;i+=2)
        {
            printf("%d ",i);
            if(i==5)
                printf("2 ");
            // if(i==n-6&&i+2!=5)
            if(i==n-6)
                printf("%d ",n-1);
        }
        printf("%d ",n);
        for(int i=n-(n&1)-2;i>=4;i-=2)
        {
            printf("%d ",i);
            if(i==n-4)
                printf("%d ",n-1);
        }
        printf("\n");
    }

}
int main()
{
    // freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
    // for(int t=read();t;t--)
    work(read());
}

F
K

L

不會啊

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章