这场的题终于补完了,开了一套,居然爆1了,打这场准掉分。

A题,跟n/2的关系有关,自己举几个例子就明白了。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
int main()
{
    int n,m;
    cin>>n>>m;
    if(m==1||m==0)
    {
        printf("1\n");
        return 0;
    }
    int d=n/2;
    int d1=n/2;
    if(n%2==1) d++;
    if(m<d)
    {
        printf("%d",m);
    }
    else{
        int t=m-d;
        int ans=d1-t;
        printf("%d",ans);
    }
}
 

B 这题题意极其的绕。大概就是求一个x使得,在前x个数中,去掉一个数,使得,剩下的数出现的次数相同。

那么定义num[i]数组为i出现的次数,f[num[i]]为 出现了num[i]次的个数

那么合法的就只有三种情况:

 1  x前面全是出现一次的数(f[1]==i)

2 出现1次的数只有一个(可以去掉这个数 f[1]==1),其他的出现的次数,选最大值(mx,f[mx]-1)*mx==i-1

3 出现的次数的最大值max(num[i]) 只有一个f[mx]==1,那么就是去掉这个mx中的一个.

使得剩下的数都是出现mx-1次。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N],f[N],num[N];
int n;
int main()
{
    cin>>n;
    rep(i,1,n) cin>>a[i];
    int ans=1,mx=0;
    rep(i,1,n)
    {
        f[num[a[i]]]--;
        num[a[i]]++;
        f[num[a[i]]]++;
        mx=max(mx,num[a[i]]);
        int ok=0;
        if(f[1]==i) ok=1;
        //else if(f[1]==mx) ok=1;
        else if(f[1]==1&&f[mx]*mx==i-1)ok=1;
        else if(f[mx]==1&&(f[mx-1]+1)*(mx-1)==i-1) ok=1;
        if(ok) ans=i;
    }
    printf("%d\n",ans);
}

C 是几何题,我以为有多难,自己仔细一搞,样例推一推就可以了。两个直线的斜率不一样,肯定是会相交的,斜率相同的直线还会出现平行的情况,这个时候求c即可 y=k*x+c  那么这里的难点就是如何去掉重合的直线。

用map<pair<int,int>,set<int> > pair保存斜率,set保存c即可。统计答案可能会有点困难。

注意分子要统一为正数,当分子为零的时候,使分母大于零。斜率不存在的情况,没关系,我用的向量保存斜率了;

pair的second为0即可。

#include<bits/stdc++.h>
using namespace std;
#define pi pair<int,int>
#define  fi first
#define  se second
const int N=1e3+10;
typedef long  long ll;
map<pi,set<int> >mp;
int n;
pi a[N];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>a[i].fi>>a[i].se;
    }
    ll ans=0,cnt=0;
    for(int i=1;i<n;++i)
    {
        for(int j=i+1;j<=n;++j)
        {
            int x1=a[i].fi,y1=a[i].se;
            int x2=a[j].fi,y2=a[j].se;
            int a=y1-y2,b=x1-x2;
            int c=x1*y2-x2*y1;
            int gc=__gcd(a,b);
            a=a/gc,b=b/gc,c=c/gc;
            if(a<0||(a==0&&b<0)) a=-a,b=-b;
            pi k=make_pair(a,b);
            if(mp[k].find(c)==mp[k].end())
            {
                cnt++;
                mp[k].insert(c);
                ans+=cnt-mp[k].size();
            }
        }
    }
    printf("%lld\n",ans);
}

D. Mysterious Code

这是个难题,我补了4个小时才会了,可能是我的dp水平太菜了吧

搜题解博客来自:

javascript:void(0)

Codeforces Round #558 (Div. 2) A、B、C(直线斜率)、D(三维字符串dp)_#include

个人感觉写的不太对,应该是dp[i][j][k] 为 c串前i个字符  匹配到了s的第j-1个字符,t的第k-1个字符,不然的话,句子中的逻辑与代码中逻辑严重不符,dp[i][0][0]就是没有匹配的

/*题意:
思路:定义dp[i][j][k]代表c串前i个字符时匹配的s串中前j个字符和t串中前k个字符
时的的答案。
dp[i+1][][] 与dp[i][][]是相互独立的。
我可以用过dp[i][][]枚举j和k,然后更新dp[i+1][][],c[i+1],找以c[i+1]为最后一个字符的
前缀,(s的前缀p,t的前缀q)//kmp算法。通过next数组找到匹配的前缀
转移方程很妙。。。。
那么状态转移方程是dp[i+1][p][q]=dp[i][j][k]+w; w 是 若匹配一个s串w++, t串w--
*/
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
const int M=60,inf=1e9;
int dp[N][M][M];
char c[N],s[M],t[M];
int next1[M],next2[M];
int n,m,len;
void get()
{
    int j=-1;
    next1[0]=-1;
    for(int i=0;i<n;)
    {
        if(j==-1||s[i]==s[j]) next1[++i]=++j;
        else j=next1[j];
    }
    j=-1;
    next2[0]=-1;
    for(int i=0;i<m;)
    {
        if(j==-1||t[i]==t[j]) next2[++i]=++j;
        else j=next2[j];
    }
}
int get1(int i,char a)
{
    while(1)
    {
        if(i==-1||s[i]==a) return i+1;
        else i=next1[i];
    }
}
int get2(int i,char a)
{
    while(1)
    {
        if(i==-1||t[i]==a) return i+1;
        else i=next2[i];
    }
}
int main()
{
    cin>>c+1>>s>>t;
    len=strlen(c+1);
    n=strlen(s);
    m=strlen(t);
    for(int i=0;i<=len;++i)
    for(int j=0;j<n;++j)
    for(int k=0;k<m;++k) dp[i][j][k]=-inf;
    get();
    dp[0][0][0]=0;
    for(int i=0;i<len;++i)
    for(int j=0;j<n;++j)
    for(int k=0;k<m;++k)
    {
        if(dp[i][j][k]==-inf)continue;
        if(c[i+1]=='*')
        {
            for(char a='a';a<='z';++a)
            {
                int p=get1(j,a);
                int q=get2(k,a);
                int w=0;
                if(p==n) w++,p=next1[p];
                if(q==m) w--,q=next2[q];
                dp[i+1][p][q]=max(dp[i+1][p][q],dp[i][j][k]+w);
            }
        }
        else{
            int p=get1(j,c[i+1]);//找前缀
            int q=get2(k,c[i+1]);
            int w=0;
            if(p==n) w++,p=next1[p];
            if(q==m) w--,q=next2[q];
            //printf("w:%d\n",w);
            dp[i+1][p][q]=max(dp[i+1][p][q],dp[i][j][k]+w);

        }
    }
    int ans=-inf;
    for(int i=0;i<n;++i)
    for(int j=0;j<m;++j) ans=max(ans,dp[len][i][j]);
    printf("%d\n",ans);
}