ccpc秦皇岛解题报告(ADFIJ)

A - Angle Beats
根据点成a点b=|a||b|cosx。当x=90度或者x=270度时,点乘等于0。于是有
x1x2+y1y2=0->x1x2=-y1y2->x1/y1=-y2/x1。于是我们分两种情况,点U是直角点,不是直角点,把x1/y1压入map,但是我们不能压浮点数,要压最简分数形式,所以还要求一次GCD,时间复杂度O(N^2*log2(n)),因为要求gcd,所以用map会炸,我们要用unordered_map。

#include<bits/stdc++.h>
#include<assert.h>
using namespace std;
typedef long long ll;
const int N=2005;
int n,q,sx,sy,x[N],y[N];
ll mul=4e9;
unordered_map<ll,int>vis[N],mp;
void cal(int &x,int &y)
{
    
    
    int k=__gcd(x,y);x/=k;y/=k;
    if(x<0) x*=-1,y*=-1;
}
int main()
{
    
    
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&x[i],&y[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
    {
    
    
        int xx=x[j]-x[i],yy=y[j]-y[i];
        if(xx==0&&yy==0) continue;
        cal(xx,yy);
        vis[i][xx*mul+yy+2e9]++;
    }
    while(q--)
    {
    
    
        scanf("%d%d",&sx,&sy);
        int ans=0;
        for(int i=1;i<=n;i++)
        {
    
    
            int xx=sx-x[i],yy=sy-y[i];
            if(xx==0&&yy==0) continue;
            swap(xx,yy);xx*=-1;
            cal(xx,yy);
            ans+=vis[i][xx*mul+yy+2e9];
        }
        mp.clear();
        int res=0;
        for(int i=1;i<=n;i++)
        {
    
    
            int xx=x[i]-sx,yy=y[i]-sy;
            if(xx==0&&yy==0) continue;
            swap(xx,yy);xx*=-1;
            cal(xx,yy);
            ans+=mp[xx*mul+yy+2e9];
            swap(xx,yy);xx*=-1;
            cal(xx,yy);
            mp[xx*mul+yy+2e9]++;
        }
        printf("%d\n",ans);
    }
}

D - Decimal
水题

#include<bits/stdc++.h>
using namespace std;
int n,t;
int main()
{
    
    
    scanf("%d",&t);
    while(t--)
    {
    
    
        scanf("%d",&n);
        while(n%2==0) n/=2;
        while(n%5==0) n/=5;
        if(n!=1) printf("Yes\n");
        else printf("No\n");
    }
}

F - Forest Program Gym
注意一条边只在一个环里,考虑在每条边选和不选,一共有2^m个状态,但是在一个环里的边我们不能全选,所以一个长度为x的环里的贡献是2的x次方减1。所以把环里的答案和环外的连乘即可。统计一个环里的边数,可以用tarjan,但是我比较懒,我就直接用LCT做了,因为环里的点数就是边数,所以在LCT时同理点u和点v的路径间点的个数即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,mod=998244353;
typedef long long ll;
ll ans=1,p[N];
int n,m,sum,root,a[N],t[N][2],fa[N],lz[N],s[N];
void pushup(int x)
{
    
    
    s[x]=s[t[x][0]]+s[t[x][1]]+1;
}
void update(int x){
    
    swap(t[x][0],t[x][1]);lz[x]^=1;}
void pushdown(int x)
{
    
    
    if(lz[x])
    {
    
    
        if(t[x][0]) update(t[x][0]);
        if(t[x][1]) update(t[x][1]);
        lz[x]=0;
    }
}
bool nroot(int x)
{
    
    
    return t[fa[x]][0]==x|t[fa[x]][1]==x;
}
void Rotate(int x)
{
    
    
    int y=fa[x],z=fa[y],k=(t[y][1]==x)^1;
    if(nroot(y)) t[z][t[z][1]==y]=x;
    t[y][k^1]=t[x][k];
    if(t[x][k]) fa[t[x][k]]=y;
    t[x][k]=y;
    fa[y]=x;
    fa[x]=z;
    pushup(y);
}
int st[N];
void splay(int x)
{
    
    
    int y=x,z=0;
    st[++z]=y;
    while(nroot(y)) st[++z]=y=fa[y];
    while(z) pushdown(st[z--]);
    while(nroot(x))
    {
    
    
        y=fa[x],z=fa[y];
        if(nroot(y)) Rotate((t[y][1]==x)^(t[z][1]==y)?x:y);
        Rotate(x);
    }
    pushup(x);
}
void access(int x)
{
    
    
    for(int y=0;x;x=fa[y=x])
    {
    
    
        splay(x);t[x][1]=y;pushup(x);
    }
}
void makeroot(int x)
{
    
    
    access(x);splay(x);update(x);
}
int findroot(int x)
{
    
    
    access(x);splay(x);
    while(t[x][0]) pushdown(x),x=t[x][0];
    splay(x);
    return x;
}
void link(int x,int y)
{
    
    
    makeroot(x);
    fa[x]=y;
}
void cut(int x,int y)
{
    
    
    makeroot(x);
    if(findroot(y)==x&&fa[y]==x&&!t[y][0])
    {
    
    
        fa[y]=t[x][1]=0;
        pushup(x);
    }
}
void split(int x,int y)
{
    
    
    makeroot(x);
    access(y);splay(y);
}
bool connect(int u,int v)
{
    
    
    makeroot(u);
    return findroot(v)==u;
}
void add(int u,int v)
{
    
    
    if(connect(u,v))
    {
    
    
        split(u,v);
        ans=ans*(p[s[v]]-1)%mod;
        sum-=s[v];
    }
    else link(u,v);
}
int main()
{
    
    
    p[0]=1;
    for(int i=1;i<N;i++) p[i]=p[i-1]*2%mod;
    scanf("%d%d",&n,&m);sum=m;
    for(int i=1;i<=m;i++)
    {
    
    
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    ans=ans*p[sum]%mod;
    printf("%lld\n",ans);
}

I - Invoker
这个不是暴力dp吗,设dp[l][i][j][k]表示放了第l个技能,最后放的技能时k,倒数第二次放的技能时j,倒数第三次放的技能时i,按的最少的次数。然后随便转移即可。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e5+5;
bool f[26][3][3][3];
int dp[N][3][3][3];
void init()
{
    
    
    f['Y'-'A'][0][0][0]=true;
    f['V'-'A'][0][0][2]=true;
    f['V'-'A'][2][0][0]=true;
    f['V'-'A'][0][2][0]=true;
    f['G'-'A'][0][0][1]=true;
    f['G'-'A'][0][1][0]=true;
    f['G'-'A'][1][0][0]=true;
    f['C'-'A'][2][2][2]=true;
    f['X'-'A'][0][2][2]=true;
    f['X'-'A'][2][0][2]=true;
    f['X'-'A'][2][2][0]=true;
    f['Z'-'A'][2][2][1]=true;
    f['Z'-'A'][1][2][2]=true;
    f['Z'-'A'][2][1][2]=true;
    f['T'-'A'][1][1][1]=true;
    f['F'-'A'][0][1][1]=true;
    f['F'-'A'][1][0][1]=true;
    f['F'-'A'][1][1][0]=true;
    f['D'-'A'][2][1][1]=true;
    f['D'-'A'][1][2][1]=true;
    f['D'-'A'][1][1][2]=true;
    f['B'-'A'][0][1][2]=true;
    f['B'-'A'][0][2][1]=true;
    f['B'-'A'][1][2][0]=true;
    f['B'-'A'][1][0][2]=true;
    f['B'-'A'][2][0][1]=true;
    f['B'-'A'][2][1][0]=true;
}
char s[N];
int main()
{
    
    
    init();
    scanf("%s",s+1);
    int n=strlen(s+1);
    memset(dp,inf,sizeof(dp));
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        for(int k=0;k<3;k++)
        dp[0][i][j][k]=3;
    for(int l=1;l<=n;l++)
    {
    
    
        int p=s[l]-'A',mn=inf;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            for(int k=0;k<3;k++)
        {
    
    
            if(f[p][i][j][k])
            dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][i][j][k]+1);
            mn=min(mn,dp[l-1][i][j][k]);
        }
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            for(int k=0;k<3;k++)
                if(f[p][i][j][k])
            {
    
    
                dp[l][i][j][k]=min(dp[l][i][j][k],mn+4);
            }
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            for(int k=0;k<3;k++)
            if(f[p][i][j][k])
            {
    
    
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][i][j][k]+1);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][0][i][j]+2);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][1][i][j]+2);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][2][i][j]+2);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][0][0][i]+3);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][0][1][i]+3);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][0][2][i]+3);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][1][0][i]+3);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][1][1][i]+3);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][1][2][i]+3);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][2][0][i]+3);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][2][1][i]+3);
                dp[l][i][j][k]=min(dp[l][i][j][k],dp[l-1][2][2][i]+3);
            }
    }
    int ans=inf;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            for(int k=0;k<3;k++)
        ans=min(ans,dp[n][i][j][k]);
    printf("%d\n",ans);
}

J - MUV LUV EXTRA
赤裸裸的kmp。可以发现A乘的就时从在第i个字符后面的字符数量,所以我们只需要最小化循环节的长度len即可,这符合kmp的性质。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
ll a,b;
int n,nex[N];
char s[N];
void kmp_init()
{
    
    
    int i=1,k=0;
    while(i<=n)
        if(k==0||s[i]==s[k]) nex[++i]=++k;
        else k=nex[k];
}
int main()
{
    
    
    scanf("%lld%lld",&a,&b);
    scanf("%s",s+1);
    n=strlen(s+1);
    reverse(s+1,s+1+n);
    while(s[n]!='.'&&n) n--;
    if(n==0)
    {
    
    
        printf("%d\n",0);return 0;
    }
    n--;
    s[n+1]='\0';
    kmp_init();
    ll ans=-1e18;
    for(int i=1;i<=n;i++)
    {
    
    
        int p=nex[i+1]-1;
        int len=i-p;
        ans=max(ans,i*a-b*len);
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/Huah_2018/article/details/102250148
今日推荐