Codeforces Round #558 (Div. 2)

A

签到,然而手残WA了一发,不过加上50分名次不变。

#include<bits/stdc++.h>
using namespace std;
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    m=n-m;
    if(m==n)printf("1");
    else if(m<=n/2)printf("%d",m);
    else printf("%d",n-m);
}
View Code

B

设前i个位置存在m种颜色,显然只有以下几种情况:1、所有颜色出现1次。2、出现最多的颜色有1种,出现次多的颜色出现次数为出现最多颜色出现次数-1,且有(m-1)种。3、出现最多的颜色种类有(m-1)种,且剩余一种颜色仅出现1次。然后维护mx的值,即为出现最多颜色出现次数,随便判一下就好了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int n,m,ans,mx,a[N],b[N],c[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        int col=a[i];
        if(b[col])c[b[col]]--;else m++;
        c[++b[col]]++;
        if(b[col]>mx)mx=b[col];
        if(m==1||mx==1||c[mx]==m-1&&c[1]==1||c[mx-1]==m-1&&c[mx]==1)ans=i;
    }
    printf("%d",ans);
}
View Code

C

可以O(n^2)枚举两两点对间的直线,记录k和b,即y=kx+b,对于不存在斜率的线,记录x坐标的位置即可。eps设为1e-10即可。然后去重,统计相同斜率的直线个数直接计算。因为答案就是斜率不同的直线对数目÷2。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1010;
struct line{double k,b;}l[N*N];
int n,num,n1,n2,m,x[N],y[N],h1[N*N],h2[N*N],b[N];
ll ans;
bool cmp(line a,line b){return fabs(a.k-b.k)<1e-10?a.b<b.b:a.k<b.k;}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>x[i]>>y[i];
    for(int i=1;i<n;i++)
    for(int j=i+1;j<=n;j++)
    if(x[i]==x[j])
    {
        if(!h1[x[i]+10000])n1++;
        h1[x[i]+10000]=1;
    }
    else l[++m].k=1.0*(y[i]-y[j])/(x[i]-x[j]),l[m].b=y[i]-l[m].k*x[i];
    sort(l+1,l+m+1,cmp);
    l[0].k=-1e18;
    for(int i=1;i<=m;i++)
    if(fabs(l[i].k-l[i-1].k)>1e-10)n2++,h2[++num]++;
    else if(fabs(l[i].b-l[i-1].b)>1e-10)n2++,h2[num]++;
    ans=1ll*n1*n2;
    for(int i=1;i<=num;i++)ans+=1ll*(n1+n2-h2[i])*h2[i];
    cout<<ans/2;
}
View Code

D

看到|c|<=1000,|s|,|t|<=50,不妨想到dp,f[i][j][k]表示c串走i步,到达|s|串j位置,|t|串k位置最大值为多少,若遇到字母直接转移,遇到*枚举26个字母。预处理s和t在每一个位置使用26个字母转移后的j/k最大值,这个暴力计算即可。复杂度O(|s|^3+|t|^3+26|c||s||t|)

#include<bits/stdc++.h>
using namespace std;
const int N=1002;
int n,ns,nt,ans=-1e9,gs[52][26],gt[52][26],f[N][52][52];
char c[N],s[N],t[N];
bool Qs(int x,int y)
{
    int p=x-y;for(int i=1;i<=y;i++)if(s[i]!=s[p+i])return 0;
    return 1;
}
bool Qt(int x,int y)
{
    int p=x-y;for(int i=1;i<=y;i++)if(t[i]!=t[p+i])return 0;
    return 1;
}
void upd(int&x,int y){x=x>y?x:y;}
int main()
{
    scanf("%s",c+1),n=strlen(c+1);
    scanf("%s",s+1),ns=strlen(s+1);
    scanf("%s",t+1),nt=strlen(t+1);
    for(int i=0;i<=ns;i++)
    for(int j=i;j>=0;j--)
    if((i!=ns||j!=ns)&&Qs(i,j))gs[i][s[j+1]-'a']=max(gs[i][s[j+1]-'a'],j+1);
    for(int i=0;i<=nt;i++)
    for(int j=i;j>=0;j--)
    if((i!=nt||j!=nt)&&Qt(i,j))gt[i][t[j+1]-'a']=max(gt[i][t[j+1]-'a'],j+1);
    for(int i=0;i<=n;i++)
    for(int j=0;j<=ns;j++)
    for(int k=0;k<=nt;k++)
    f[i][j][k]=-1e9;
    f[0][0][0]=0;
    for(int i=1;i<=n;i++)
    for(int j=0;j<=ns;j++)
    for(int k=0;k<=nt;k++)
    if(f[i-1][j][k]>-1e9)
    {
        if(c[i]!='*')
        {
            int x=c[i]-'a';
            upd(f[i][gs[j][x]][gt[k][x]],f[i-1][j][k]+(gs[j][x]==ns)-(gt[k][x]==nt));
        }
        else for(int x=0;x<26;x++)
        upd(f[i][gs[j][x]][gt[k][x]],f[i-1][j][k]+(gs[j][x]==ns)-(gt[k][x]==nt));
    }
    for(int j=0;j<=ns;j++)
    for(int k=0;k<=nt;k++)
    upd(ans,f[n][j][k]);
    printf("%d",ans);
}
View Code

E

太难了,很少有这么难的E。考虑从小到大枚举2的幂次,当答案是x时,然后将每个小于2x的a[i]插入线性基。判断从0~x-1位是否存在即可。找到最大的x后,再重建立一遍线性基,dfs搜索答案即可,每次异或线性基内的数。复杂度O(nlogn),因为可以two-pointers,其中n=max{a[i]}。

#include<bits/stdc++.h>
using namespace std;
const int N=270000;
int n,ans,a[N],b[20],vis[N];
vector<int>G;
void add(int v)
{
    int tmp=v;
    for(int i=19;i>=0;i--)
    if(v&(1<<i))
    {
        if(b[i])v^=b[i];
        else{G.push_back(tmp),b[i]=v;break;}
    }
}
void dfs(int v,int t)
{
    printf("%d ",v);
    vis[v]=1;
    if(t==(1<<ans))return;
    for(int i=0;i<G.size();i++)if(!vis[v^G[i]]){dfs(v^G[i],t+1);break;}
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1,p=1;i<=19;i++)
    {
        while(p<=n&&a[p]<(1<<i))add(a[p++]);
        bool flag=1;
        for(int j=0;j<i;j++)if(!b[j])flag=0;
        if(flag)ans=i;
    }
    memset(b,0,sizeof b);
    G.clear();
    for(int i=1;i<=n;i++)if(a[i]<(1<<ans))add(a[i]);
    printf("%d\n",ans);
    sort(G.begin(),G.end());
    unique(G.begin(),G.end());
    dfs(0,1);
}
View Code

F

太难了,先咕着。

这场CF是真心难,所以导致其成为手速场,体现不了选手的真实水平。用小号的小号打的,就会ABCD,rank5,rating+=291。感觉自己稍微有点难度的题都不会。

转载于:https://www.cnblogs.com/hfctf0210/p/10842345.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值