码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round #522 Div. 1 没打记

时间:2018-11-19 21:43:27      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:namespace   方案   algorithm   col   return   printf   splay   log   一个   

  开场被A劝退,写了得有50min于是不敢交了。unrated了喜闻乐见。

  A:瞎猜都能猜到如果要走到那条直线上,进入直线的点横坐标或纵坐标与起点相同,离开直线的点横坐标或纵坐标与终点相同,证明脑补一下比较显然。看错题以为到直线上的那个点必须是整点,于是搞了半天exgcd。然而就算这样也不至于写这么长时间啊根本不知道自己在干啥。

技术分享图片
#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define double long double
char getc(){char c=getchar();while ((c<A||c>Z)&&(c<a||c>z)&&(c<0||c>9)) c=getchar();return c;}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
    while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
double ans,A,B,C,lx,ly,rx,ry;
double dis_m(double x,double y,double p,double q){return fabs(x-p)+fabs(y-q);}
double dis_o(double x,double y,double p,double q){return sqrt((p-x)*(p-x)+(y-q)*(y-q));}
struct data{double x,y;
}a[2],b[2];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif
    A=read(),B=read(),C=read();
    lx=read(),ly=read(),rx=read(),ry=read();
    ans=fabs(rx-lx)+fabs(ry-ly);
    if (A&&B)
    {
        a[0].x=lx,a[0].y=(-C-A*lx)/B;
        a[1].y=ly,a[1].x=(-C-B*ly)/A;
        b[0].x=rx,b[0].y=(-C-A*rx)/B;
        b[1].y=ry,b[1].x=(-C-B*ry)/A;
        for (int i=0;i<2;i++)
            for (int j=0;j<2;j++)
            ans=min(ans,dis_m(lx,ly,a[i].x,a[i].y)+dis_o(a[i].x,a[i].y,b[j].x,b[j].y)+dis_m(b[j].x,b[j].y,rx,ry));
    }
    printf("%.6Lf\n",ans);
    return 0;
}
View Code

  B:题意比较奇怪,做法相当显然,肯定要保证所有满足询问给出的条件的子集都只包含同一单一数字,类似背包的算一发方案数就行了,可以取个模。看起来询问补集也是一种询问方式,不过稍微想一下就知道是没有必要的。但这带来一种特殊情况,即只有两种数字时输出n。

技术分享图片
#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 110
#define P 998244353 
char getc(){char c=getchar();while ((c<A||c>Z)&&(c<a||c>z)&&(c<0||c>9)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
    while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,a[N],ans;
int f[N][N*N],C[N][N];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
#endif
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    f[0][0]=1;
    for (int i=1;i<=n;i++)
        for (int k=i;k>=1;k--)
            for (int j=10000;j>=a[i];j--)
            f[k][j]=(f[k][j]+f[k-1][j-a[i]])%P;
    C[0][0]=1;
    for (int i=1;i<=n;i++)
    {
        C[i][0]=C[i][i]=1;
        for (int j=1;j<i;j++)
        C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
    }
    sort(a+1,a+n+1);
    int cnt=0;
    for (int i=1;i<=n;i++)
    {
        int t=i;
        cnt++;
        while (t<n&&a[t+1]==a[i]) t++;
        for (int j=i;j<=t;j++)
        if (C[t-i+1][j-i+1]==f[j-i+1][(j-i+1)*a[i]]) ans=max(ans,j-i+1);
        i=t;
    }
    if (cnt==2) {cout<<n;return 0;}
    cout<<ans;
    return 0;
}
View Code

  C:考虑清楚最大匹配唯一究竟是什么。冷静分析能够发现其充要条件是该树只包含一个点或存在完美匹配。充分性比较显然,对于必要性,考虑如果不存在完美匹配,最大匹配中未匹配点的周围一定存在匹配点,可以将该匹配点改为与未匹配点匹配而匹配数不变,于是方案不唯一。那么就可以瞎dp了,我自己的做法是设f[i][0/1/2]分别表示 割开i与父亲的边,子树内的森林都满足条件/不割开i与父亲的边,i不与子树内点匹配/不割开i与父亲的边,i与子树内点匹配 的删边方案数,比较显然的有f[i][2]=Σ(f[k][1]·∏(f[son][0]+f[son][2])) (k为i某个儿子,son为除k以外i的儿子们) f[i][0]=f[i][2]+∏f[son][0] f[i][1]=∏(f[son][0]+f[son][2])。

技术分享图片
#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 300010
#define P 998244353
char getc(){char c=getchar();while ((c<A||c>Z)&&(c<a||c>z)&&(c<0||c>9)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
    while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,p[N],f[N][3],pre[N],suf[N],t;
struct data{int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k,int from)
{
    f[k][0]=f[k][1]=1;f[k][2]=0;int son=0;pre[0]=1;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=from) dfs(edge[i].to,k);
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=from) pre[++son]=(f[edge[i].to][0]+f[edge[i].to][2])%P;
    suf[son+1]=1;for (int i=1;i<=son;i++)suf[i]=pre[i];
    for (int i=1;i<=son;i++) pre[i]=1ll*pre[i-1]*pre[i]%P;
    for (int i=son;i>=1;i--) suf[i]=1ll*suf[i+1]*suf[i]%P;
    int cnt=0;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=from)
    {
        cnt++;
        f[k][2]=(f[k][2]+1ll*f[edge[i].to][1]*pre[cnt-1]%P*suf[cnt+1])%P;
        f[k][0]=1ll*f[k][0]*f[edge[i].to][0]%P;
    }
    f[k][0]=(f[k][0]+f[k][2])%P;
    f[k][1]=pre[son];
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
#endif
    n=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y),addedge(y,x);
    }
    dfs(1,1);
    cout<<f[1][0];
    return 0;
}
View Code

  D:https://www.cnblogs.com/Gloid/p/9874122.html 可能和这个题比较相似。倍增算出每只鹦鹉的影响区间扩展2k次能到哪即可。只是口胡,不知道有没有锅。

Codeforces Round #522 Div. 1 没打记

标签:namespace   方案   algorithm   col   return   printf   splay   log   一个   

原文地址:https://www.cnblogs.com/Gloid/p/9985267.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!