[20180819]四校联考

不要问我8.19的题为什么今天才写完,因为我弱啊

T1 扫雷(mine)

Problem戳这里

Solution:


显然,\(ans = min_{i=1}^n \frac{bi}{ai}\),令cnt为满足ans的个数,方案数即\(2^{cnt }-1\),用快速幂来求。

另外,本题卡精度,你当然可以向XMJJSW一样写一个分数类,也可以对输入的数成\(10^8\), 用整形判断

不过最方便的还是设个eps,取个1e-12即可以了。


#include<iostream>
#include<cstdio>
#include<algorithm>
#define MN 1000005
double a[MN],b[MN];
long long num,n,ans;
#define mod 998442553
#define eps 1e-12 
#define sign(a) ((a>(-eps))-(a<eps))
inline bool cmp(const int&x,const int&y){
    return sign(a[x]*b[y]-b[x]*a[y])==1;
}
long long Quick_pow(long long m,long long p){
    long long res=1;
    while(p){
        if(p&1) res=(res*m)%mod,p-=1;
        else m=(m*m)%mod,p>>=1;
    }
    return res;
}
int main(){
    freopen("mine.in","r",stdin);
    freopen("mine.out","w",stdout);
    int T;scanf("%d\n",&T);
    while(T--){
        scanf("%d",&n);register int i;
        for(i=1;i<=n;i++) scanf("%lf",&a[i]);
        for(i=1;i<=n;i++) scanf("%lf",&b[i]);
        ans=1;num=0;
        for(i=2;i<=n;i++) if(cmp(i,ans)) ans=i;
        for(i=1;i<=n;i++){
            if(sign(a[i]*b[ans]-a[ans]*b[i])==0) num++;
        }
        if(sign(b[ans]-a[ans]*10000.0)==1){
            puts("Impossible");continue;
        }
        num=(Quick_pow(2,num)+mod-1)%mod;
        printf("%.8lf %lld\n",b[ans]/a[ans],num);
    }
    return 0;
}




T2 信息组的裁员(cut)

Problem戳这里

Solution:


对于30%的数据,可以使用O(\(m^2\))的简单dp。

对于60%的数据,可以贪心,也很好想。

对于100%的数据,考虑贪心的优化。

官方题解:

1129554-20180823235306890-790915268.png
1129554-20180823235200373-1857318602.png

嗯,完美。


//30分的dp
#include<iostream>
#include<cstdio>
#include<algorithm>
inline long long read(){
    long long x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 6000005
long long n,m,a[MN],q[MN];
long long num,sum,f[2][MN];
int main(){
    freopen("cut.in","r",stdin);
    freopen("cut.out","w",stdout);
    n=read();m=read();
    register int i,j;
    for(i=1;i<=n;i++) a[i]=read(),q[i]=q[i-1]+a[i];
    for(i=1;i<=n;i++) if(a[i]>=0){
        j=i;num++;while(a[i+1]>=0&&i<n) i++;
        sum+=q[i]-q[j-1];
    }
    if(num<=m) return 0*printf("%lld\n",sum);
    int now=1,last=0;
    for(i=1;i<=n-m+1;i++) f[0][i]=std::max(f[0][i-1],q[i]);
    for(i=2;i<=m;i++){
        f[now][i]=q[i];
        for(j=i+1;j<=i+n-m;j++) f[now][j]=a[j]+std::max(f[now][j-1],f[last][j-1]);
        for(j=i+1;j<=i+n-m;j++) f[now][j]=std::max(f[now][j-1],f[now][j]);
        now^=1;last^=1;
    }
    printf("%lld\n",f[last][n]);
    return 0;
}



#include<bits/stdc++.h>
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define abs(a) (((a)>0)?(a):-(a))
#define cmin(a,b) (a>(b)?a=(b),1:0)
#define cmax(a,b) (a<(b)?a=(b),1:0)
#define dmin(a,b) ((a)<(b)?(a):(b))
#define dmax(a,b) ((a)>(b)?(a):(b))
typedef long long ll;
#define MN 6000005
struct data{
    ll val;int pos;
    data(ll v=0,int p=0){val=v;pos=p;}
    bool operator< (const data &o) const{return val<o.val||val==o.val&&pos<o.pos;}
    bool operator<=(const data &o) const{return val<o.val||val==o.val&&pos<=o.pos;}
}t[MN],mx,mx2;
ll a[MN],ans;
int remain,n,m,q[MN],hq,tq,cnt,l[MN],r[MN],L[MN],R[MN];
bool inq[MN],del[MN],Del[MN];
void AddQue(int i){
    if(i&&(!inq[i])&&data(abs(a[i]),i)<=mx) q[++tq]=i,inq[i]=true;
}
void dele(int x){
    if((!x)||del[x]) return ;
    r[l[x]]=r[x];l[r[x]]=l[x];
    del[x]=true;
}
void Dele(int x){
    if((!x)||Del[x]) return ;
    remain--;R[L[x]]=R[x];L[R[x]]=L[x];
    Del[x]=true;dele(x);
}
void Merge(int x){
    if(Del[x]) return ;
    int lef=L[x],rig=R[x];
    if(lef&&abs(a[lef])<abs(a[x])) return ;
    if(rig&&abs(a[rig])<abs(a[x])) return ;
    Dele(lef);Dele(rig);a[x]+=a[lef]+a[rig];
    lef&&rig?AddQue(x):Dele(x);
    AddQue(lef);AddQue(rig); 
}
int main(){
    freopen("cut.in","r",stdin);
    freopen("cut.out","w",stdout);
    n=read();m=read();int i,j,x;
    for(i=1,j=0;i<=n;i++){
        a[++j]=read();if(a[j]==0||j==1&&a[j]<0)--j;
        if(j>1&&(a[j]>0)^(a[j-1]<0)) a[j-1]+=a[j],--j; 
    }if(j>0&&a[j]<0) --j;
    for(i=0;i<=j;i++)
        r[i]=R[i]=(i+1)%(j+1),l[i]=L[i]=(i+j)%(j+1);
    remain=j;
    while(1){
        cnt=0;hq=1;tq=0;
        for(i=r[0];i;i=r[i]) t[++cnt]=data(abs(a[i]),i);
        if(remain<(m<<1)) break;
        int mid=(remain-(m<<1)+1)>>1;
        std::nth_element(t+1,t+dmin(mid,cnt)+1,t+cnt+1);
        mx=t[dmin(mid,cnt)];
        std::nth_element(t+1,t+dmin(mid*3,cnt)+1,t+cnt+1);
        mx2=t[dmin(mid*3,cnt)];
        for(i=r[0];i;i=r[i]){
            data cur(abs(a[i]),i);
            if(mx2<cur) dele(i);
            else AddQue(i);
        }
        for(;hq<=tq;++hq)
            inq[q[hq]]=false,Merge(q[hq]);
    }ans=0;
    for(i=R[0];i;i=R[i]) if(a[i]>0) ans+=1ll*a[i];
    printf("%lld\n",ans);
    return 0;
}




T3 已傻的结合(ishhac)

Problem戳这里

Solution:


  1. dp方程:(a=0的时候)

    \[f_{k,i,j}=min_{x}^n\ max \{f_{k-1,i,x},g_{x,j}\}\]其中,g[x][j]表示x到j的边权。

  2. 方程转移的过程,可以用类似矩阵快速幂的方式

  3. 因为T<=4,所以图的一个周期是12,所以\[G_i=G_{i \ mod \ 12}\].

    分别求出这12个矩阵,命名为A1~A12,则最终矩阵是

    \[R= A_{12}^{\left\lfloor\frac{K}{12}\right\rfloor}\Phi A_{K\ mod\ 12}\]

    用矩阵快速幂求\(A_{12}^{\left\lfloor\frac{K}{12}\right\rfloor}\)即可。


膜一下大佬的代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
typedef long long LL;
LL ri() {
    char c = getchar(); LL x = 0; for(;c < '0' || c > '9'; c = getchar()) ;
    for(;c >= '0' && c <= '9';  c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x;
}
struct Maxtir {
    int n, m[60][60];
    void Init() {n = 0; std::memset(m, 0x3f, sizeof(m));}
    Maxtir operator * (Maxtir a) {
        Maxtir b; b.n = a.n;
        for(int i = 1;i <= n; ++i)
            for(int j = 1;j <= n; ++j) {
                b.m[i][j] = inf;
                for(int k = 1;k <= n; ++k)
                    b.m[i][j] = std::min(b.m[i][j], std::max(a.m[k][j], m[i][k]));
            }
        return b;
    }
}a, b, c[13];
int n, m, s, t; LL K;
void Pow(Maxtir &a, LL x) {Maxtir b = a; x--; for(;x; b = b * b, x >>= 1) if(x & 1) a = a * b;}
int main() {
    freopen("ishaac.in","r",stdin);
    freopen("ishaac.out","w",stdout);
    for(int C = ri(); C--;) {
        a.Init(); n = ri(); m = ri(); s = ri(); t = ri(); K = ri(); a.n = n;
        for(int i = 1, u, v, w;i <= m; ++i)
            u = ri(), v = ri(), w = ri(), a.m[u][v] = a.m[v][u] = w;
        for(int i = 1;i <= 12; ++i) c[i] = a;
        int nf = ri();
        for(int i = 1, T, j, x, k;i <= nf; ++i)
            for(T = ri(), j = 0;j < T; ++j)
                for(x = ri(), k = j;k <= 12; k += T)
                    for(int p = 1;p <= n; ++p)
                    c[k].m[p][x] = inf;
        a = c[1];
        if(K <= 12) {
            for(int i = 2;i <= K; ++i) a = a * c[i];
            a.m[s][t] == inf ? puts("impossible") : printf("%d\n", a.m[s][t]);
            continue;
        }
        for(int i = 2;i <= 12; ++i) a = a * c[i];
        Pow(a, K / 12);
        for(int i = 1;i <= K % 12; ++i) a = a * c[i];
        a.m[s][t] == inf ? puts("impossible") : printf("%d\n", a.m[s][t]);
    }
    return 0;
}





Blog来自PaperCloud,未经允许,请勿转载,TKS!

转载于:https://www.cnblogs.com/PaperCloud/p/9527320.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值