SDOI2013 R1 Day2

Posted SovietPower

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOI2013 R1 Day2相关的知识,希望对你有一定的参考价值。

2018. Test

时间:7:30~11:30 (最后半小时不做了)
期望得分:50+100+20=170
实际得分:40+44+20=104

总结

T1

题目链接

T2 洛谷.3305.[SDOI2013]费用流(最大流ISAP 二分)

题目链接(BZOJ无SPJ)

题意即是求满足最大流条件下 使得流量最大的边尽量小。花费显然是最大的某条边上的流量*P。
但P是实数范围内!这说明流量也是实数,二分答案跑最大流检验。限制的话,直接重设流量。
贪心的话最大流过程中流量一直是整数,所以就GG了。。

#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const double eps=1e-6;
const int N=218,M=2018;

int n,m,P,Max,src,des,Enum,H[N],cur[N],fr[M],to[M],nxt[M],cost[M],num[N],lev[N],pre[N],que[N];
double cap[M],Cap[M];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline void AddEdge(int u,int v,int w)
{
    Max=std::max(Max,w);
    to[++Enum]=v, fr[Enum]=u, nxt[Enum]=H[u], H[u]=Enum, Cap[Enum]=cap[Enum]=w;
    to[++Enum]=u, fr[Enum]=v, nxt[Enum]=H[v], H[v]=Enum, Cap[Enum]=cap[Enum]=0; 
}
bool BFS()
{
    for(int i=src; i<des; ++i) lev[i]=des+1;
    lev[des]=0, que[0]=des; int h=0,t=1;
    while(h<t)
    {
        int x=que[h++];
        for(int i=H[x]; i; i=nxt[i])
            if(lev[to[i]]==des+1 && cap[i^1])
                lev[to[i]]=lev[x]+1, que[t++]=to[i];
    }
    return lev[src]<=des;
}
double Augment()
{
    double mn=1e8;
    for(int i=des; i!=src; i=fr[pre[i]])
        mn=std::min(mn,cap[pre[i]]);
    for(int i=des; i!=src; i=fr[pre[i]])
        cap[pre[i]]-=mn, cap[pre[i]^1]+=mn;
    return /*fabs(mn)<eps?0:*/mn;
}
double ISAP()
{
    if(!BFS()) return 0;
    for(int i=src; i<=des; ++i) ++num[lev[i]],cur[i]=H[i];
    int x=src; double res=0;
    while(lev[src]<=des)
    {
        if(x==des) x=src,res+=Augment();
        bool can=0;
        for(int i=cur[x]; i; i=nxt[i])
            if(lev[to[i]]==lev[x]-1 && cap[i])
            {
                can=1, cur[x]=i, pre[x=to[i]]=i;
                break;
            }
        if(!can)
        {
            int mn=des;
            for(int i=H[x]; i; i=nxt[i])
                if(cap[i]) mn=std::min(mn,lev[to[i]]);
            if(!--num[lev[x]]) break;
            ++num[lev[x]=mn+1];
            cur[x]=H[x];
            if(x!=src) x=fr[pre[x]];
        }
    }
    return res;
}
void Init(double lim){
    for(int i=2; i<=Enum; ++i) cap[i]=std::min(Cap[i],lim);
}
double Solve(double mxflow)
{
    double l=1.0,r=Max,m;
    while(r-l>1e-4)
        if(Init(m=(l+r)*0.5),fabs(mxflow-ISAP())<eps) r=m;
        else l=m;
    return l;
}

int main()
{
    n=read(),m=read(),P=read(),Enum=src=1,des=n;
    for(int u,v,w,i=1; i<=m; ++i)
        u=read(),v=read(),w=read(),AddEdge(u,v,w);//f&=(w==1);
    double res1=ISAP();
    printf("%.0lf\n%.4lf",res1,1.0*Solve(res1)*P);

    return 0;
}

T3

题目链接

考试代码

T1

恶心的Lucas+Ex_Lucas。

#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=2e4+23;

int n,n1,n2,m,A[10],B[10],fac[N],f[10][N],sum[N],cnt,pi[666],pk[666];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
LL FP(LL x,int k,LL p)
{
    LL t=1ll;
    for(; k; k>>=1,x=x*x%p)
        if(k&1) t=t*x%p;
    return t;
}
void Exgcd(int a,int b,int &x,int &y)
{
    if(!b) x=1,y=0;
    else Exgcd(b,a%b,y,x),y-=a/b*x;
}
inline LL inv(int a,int p)
{
    int x,y; Exgcd(a,p,x,y);
    return (LL)((x%p+p)%p);
}
LL Calc(int n,int m,int p)
{
    if(n<m) return 0ll;
    return 1ll*fac[n]*inv(fac[m],p)%p*inv(fac[n-m],p)%p;
}
LL Lucas(int n,int m,int p)//p=10007
{
//  printf("Lucas:C(%d,%d) mod %d = ",n,m,p);
    if(n<m) return 0ll;
    LL res=1;
    for(; m&&res; n/=p,m/=p)
        (res*=Calc(n%p,m%p,p))%=p;
//  printf("%d\n",res);
    return res;
}
LL Fact(int n,int pi,int pk)
{
    if(!n) return 1ll;//边界! 
    LL res=1ll;
    if(n>=pk)
    {
        for(int i=2; i<pk; ++i)
            if(i%pi) (res*=i)%=pk;
        res=FP(res,res/pk,pk);
    }
    for(int i=2; i<=n%pk; ++i)
        if(i%pi) (res*=i)%=pk;
    return res*Fact(n/pi,pi,pk)%pk;
}
LL C(int n,int m,int pi,int pk,int mod)
{
    LL a=Fact(n,pi,pk),b=Fact(m,pi,pk),c=Fact(n-m,pi,pk);int k=0;
    for(int i=n; i; i/=pi) k+=i/pi;
    for(int i=m; i; i/=pi) k-=i/pi;
    for(int i=n-m; i; i/=pi) k-=i/pi;
    LL res=a*inv(b,pk)%pk*inv(c,pk)%pk*FP(pi,k,pk)%pk;
    return res*(mod/pk)%mod*inv(mod/pk,pk)%mod;
}
LL Ex_Lucas(int n,int m,int p)
{
//  printf("Ex_Lucas:C(%d,%d) mod %d = ",n,m,p);
    if(n<m) return 0ll;
    if(n==m) return 1ll;
    int res=0;
    for(int i=1; i<=cnt; ++i)
        (res+=C(n,m,pi[i],pk[i],p))%=p;
//  printf("%d\n",res);
    return (LL)res;
}
void Init_P(int p)
{
    for(int i=2,m=sqrt(p+1); i<=m; ++i)
        if(!(p%i))
        {
            int pk_=1;
            while(!(p%i)) p/=i,pk_*=i;
            pi[++cnt]=i, pk[cnt]=pk_;
            if(p==1) break;
        }
}

int main()
{
    freopen("equation.in","r",stdin);
    freopen("equation.out","w",stdout);

    int T=read(),p=read();
    fac[0]=1;
    if(p==10007)
        for(int x,y,i=1; i<p; ++i) fac[i]=fac[i-1]*i%p;
    else Init_P(p);
    while(T--)
    {
        n=read(),n1=read(),n2=read(),m=read()-n+n2;
        LL tot=0;
        for(int i=1; i<=n1; ++i) A[i]=read()-1,tot+=A[i];
        for(int i=1; i<=n2; ++i) B[i]=read(),m-=B[i];
//      printf("1: n:%d m:%d\n",n,m);
        if(m<0) {puts("0"); continue;}
        if(!m) {puts("1"); continue;}
        if(m==1)
        {
            int res=n;
            for(int i=1; i<=n1; ++i) if(!A[i]) --res;
            printf("%d\n",res);
            continue;
        }
        A[n1+1]=0;
        for(int j=0; j<=A[1]; ++j) f[1][j]=1;
        sum[0]=1;
        for(int j=1; j<=A[1]+A[2]; ++j) sum[j]=sum[j-1]+f[1][j];
        for(int tmp=A[1],tmp2=A[1]+A[2],i=2; i<=n1; ++i)//O(8m)
        {
            tmp+=A[i], f[i][0]=1;
            for(int j=1; j<=tmp; ++j)
            {
                if(j<std::min(j,A[i])) f[i][j]=sum[j];
                else f[i][j]=sum[j]-sum[j-std::min(j,A[i])-1], f[i][j]=(f[i][j]%p+p)%p;
//              printf("f[%d][%d]:%d %d bef:%d %d\n",i,j,f[i][j],p,sum[j],sum[j-std::min(j-1,A[i])-1]);
            }
            tmp2+=A[i+1], sum[0]=1;
            for(int j=1; j<=tmp2; ++j)
            {
                sum[j]=sum[j-1]+f[i][j];
                if(sum[j]>=p) sum[j]-=p;
            }
        }
        LL res=0; f[n1][0]=1;
//      printf("2: n:%d m:%d\n",n,m);
        tot=std::min(tot,(LL)m);
//      for(int i=0; i<=tot; ++i) printf("f:%d:%d\n",i,f[n1][i]);
        if(p==10007) for(int i=0; i<=tot; ++i) (res+=1ll*f[n1][i]*Lucas(n+m-i-n1-1,m-i,p))%=p;
        else for(int i=0; i<=tot; ++i) (res+=1ll*f[n1][i]*Ex_Lucas(n+m-i-n1-1,m-i,p))%=p;
        printf("%I64d\n",res);
    }
    return 0;
}

T2

答案都比标程正好大了一倍,气啊。

#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=218,M=2018,INF=0x3f3f3f3f;

int n,m,P,Max,src,des,Enum,H[N],cur[N],fr[M],to[M],cap[M],nxt[M],cost[M],num[N],lev[N],pre[N],que[N];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline void AddEdge(int u,int v,int w)
{
    to[++Enum]=v, fr[Enum]=u, nxt[Enum]=H[u], H[u]=Enum, cap[Enum]=w;
    to[++Enum]=u, fr[Enum]=v, nxt[Enum]=H[v], H[v]=Enum, cap[Enum]=0;   
}
bool BFS()
{
    for(int i=src; i<des; ++i) lev[i]=des+1;
    lev[des]=0, que[0]=des; int h=0,t=1;
    while(h<t)
    {
        int x=que[h++];
        for(int i=H[x]; i; i=nxt[i])
            if(lev[to[i]]==des+1 && cap[i^1])
                lev[to[i]]=lev[x]+1, que[t++]=to[i];
    }
    return lev[src]<=des;
}
int Augment()
{
    int mn=INF;
    for(int i=des; i!=src; i=fr[pre[i]])
        mn=std::min(mn,cap[pre[i]]);
    for(int i=des; i!=src; i=fr[pre[i]])
        cap[pre[i]]-=mn, cap[pre[i]^1]+=mn;
//  printf("Augment:%d\n",mn);
//  Max=std::max(Max,mn);
    return mn;
}
int ISAP()
{
    if(!BFS()) return 0;
    for(int i=src; i<=des; ++i) ++num[lev[i]],cur[i]=H[i];
    int x=src,res=0;
    while(lev[src]<=des)
    {
        if(x==des) x=src,res+=Augment();
        int way=0,mn=0;
        for(int i=cur[x]; i; i=nxt[i])
            if(lev[to[i]]==lev[x]-1 && cap[i])
                if(!mn) way=mn=i;
                else if(cap[way]>cap[i]) way=i;
        if(way) cur[x]=mn, pre[x=to[way]]=way;
        else
        {
            int mn=des;
            for(int i=H[x]; i; i=nxt[i])
                if(cap[i]) mn=std::min(mn,lev[to[i]]);
            if(!--num[lev[x]]) break;
            ++num[lev[x]=mn+1];
            cur[x]=H[x];
            if(x!=src) x=fr[pre[x]];
        }
    }
    return res;
}

int main()
{
    freopen("costflow.in","r",stdin);
    freopen("costflow.out","w",stdout);

    n=read(),m=read(),P=read(),Enum=src=1,des=n;
    for(int u,v,w,i=1; i<=m; ++i)
        u=read(),v=read(),w=read(),AddEdge(u,v,w);//f&=(w==1);
    int res1=ISAP();
//  if(f) {printf("%d\n%d.0000",res1,P); return 0;}
    for(int i=3; i<=Enum; i+=2) Max=std::max(Max,cap[i]);//应是从最大流后全局的反向弧找Max 
    printf("%d\n%d.0000",res1,Max*P);

    return 0;
}

T3

#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
#define mod (1000000007)
typedef long long LL;
const int N=1e6+7;

int K,f[N+3],sum[1005][1005];//size!
LL n;
std::priority_queue<int> q;

void Violence()
{
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=n; ++j)
            ++sum[f[i]][f[j]];
    for(int i=1; i<=n; ++i)
        for(int j=1; j<=n; ++j)
            if(sum[i][j]) q.push(sum[i][j]);
//  for(int i=1; i<=n; ++i,putchar('\n'))
//      for(int j=1; j<=n; ++j)
//          printf("%d ",sum[i][j]);
    LL res=0;
    while(K-- && !q.empty()) res+=q.top(),q.pop();
    printf("%I64d",res%mod);
}

int main()
{
    freopen("gold.in","r",stdin);
    freopen("gold.out","w",stdout);

    scanf("%I64d%d",&n,&K);
    f[0]=1;
    for(int i=1; i<N; ++i)
        if(i%10) f[i]=f[i/10]*(i%10);
        else f[i]=0;
    f[0]=0;
//  for(n=100; n<=300; ++n,putchar('\n'))
//      memset(sum,0,sizeof sum),printf("%I64d:\t",n),Violence();
    if(n<=1000) {Violence(); return 0;}
    printf("%d",rand()%mod);

    return 0;
}

以上是关于SDOI2013 R1 Day2的主要内容,如果未能解决你的问题,请参考以下文章

SDOI2017 R2 Day2

SDOI2017 Round1 Day2 题解

BZOJ4513~4518 SDOI2016 R1 题解

「SDOI2013」森林

NOIP2013 DAY2题解

COGS 723. [SDOI2007] 超级数组