1. 程式人生 > >test20181021-day1(九校聯考)

test20181021-day1(九校聯考)

題解尚未出,先口胡一波

T1

讀題,曰:"普及組裸題."大喜,遂敲完全揹包,小樣例全然無異,心得意滿,以為A之

然後...


這...n,m巨大,貌似不可做.但此題有一個突出的性質,\(a,b \leq 100\).於是欲以其做文章.去重後其實只有10000個物品,這樣有40分...
然後又根據一種神奇的思想: 如果一個選手比你小還比你強,你就可以退役了 ,可以刪去許多無用的物品.
考場上寫了個二維樹狀陣列亂搞,但後來學長告訴我只能刪體積有倍數關係的一些點.
在我的亂搞冷靜分析後,物品數n其實已經比較小了,但是m仍舊很大.乃口胡一性質,貪心放入物品直至m降到1e5,再跑完全揹包..

這樣的正確性應該是得不到保證的,但好像資料比較水,就,就A了..

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) x&(-x)
using namespace std;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>='0'&&jp<='9')
        {
            out=out*10+jp-'0';
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=1e6+10;
int n,len=0;
ll m,ans=0;
bool bit[250][250];
ll f[101000]={0};
inline void add(int x,int y)
{
    for(int i=x;i<=101;i+=lowbit(i))
        for(int j=y;j<=100;j+=lowbit(j))
            bit[i][j]=1;
}
inline int sum(int x,int y)
{
    int s=0;
    for(int i=x;i;i-=lowbit(i))
        for(int j=y;j;j-=lowbit(j))
                s+=bit[i][j];
    return s;   
}
struct node{
    int a,b;//體積,價值 
    bool operator == (const node& rhs) const {
        return (a==rhs.a && b==rhs.b);
    }
    bool operator < (const node& rhs) const {
        return (b*rhs.a>a*rhs.b);
    }
}Q[MAXN],P[MAXN];
int main()
{
    freopen("backpack.in","r",stdin);
    freopen("backpack.out","w",stdout);
    scanf("%d%lld",&n,&m);
    for(int i=0;i<n;++i)
        {
            Q[i].a=read();
            Q[i].b=read();  
        }
    n=unique(Q,Q+n)-Q;
    for(int i=0;i<n;++i)
        add(102-Q[i].b,Q[i].a);
    for(int i=0;i<n;++i)
        {
            int k=sum(102-Q[i].b,Q[i].a);
            if(k<2)
                {
                    P[len].a=Q[i].a;
                    P[len].b=Q[i].b;
                    ++len;
                }
        }
    n=len;
    sort(P,P+n);
    ll t=max(1ll*0,(m-100000)/P[0].a);
    m-=1ll*P[0].a*t,ans+=1ll*P[0].b*t;
    for(int i=0;i<n;++i)
        for(int j=P[i].a;j<=m;++j)
            f[j]=max(f[j],f[j-P[i].a]+P[i].b);
    cout<<f[m]+ans;
    return 0;
}

T2

資料範圍 \(n,m \leq 5e5\),操作保證了不會爆long long.

題面好長啊...
開始沒理解到"這個序列有序",以為是每次修改後每個數的rank不變,卡了好久 ,後來發現就是指這個序列是遞增的...
這樣的話,

最大值是後半段減前半段,顯然用線段樹維護;

最小值是區間中的偶數位置的和減去區間中的奇數位置的和,考試時想了一會,又開了一顆線段樹,維護\(c[2]-c[1],c[4]-c[3]...c[2*n]-c[2*n-1]\)這樣一個類似差分的序列.

修改區間[L,R]時,如果L是奇數,就不用處理;如果是偶數,就要在L/2的位置加上val,在(R+1)/2的位置減去val,類似差分的操作.
回答詢問[L,R]時,如果L是奇數,那麼就直接查詢區間和;如果是偶數,就算出[L+1,R-1]的值,乘上-1,加上R位置的值,再減去L位置的值,這樣調整得到答案.
考完後才知道這做法很sb...直接同時維護區間奇數位置和,偶數位置和,總和,合併的時候注意下就好了...
還好在後面的大力除錯之下,我這sb做法沒有出問題...

至於方案總數,個人覺得是這三個中最難想的...

容易知道方案數只與區間長度有關,看來是一個數學式子...手算了前5項,開始算成了\(1,2,5,15,42\),死活沒看出來...
然後猜到懷疑人生,驗算一波,發現第4項應該是14...
\(1,2,5,14,42\),Catalan數吧...然後怒敲200+行,開始除錯,有驚無險A了此題...

#include<bits/stdc++.h>
#define ll long long
#define root Tree[o]
#define lson Tree[o<<1]
#define rson Tree[o<<1|1]
using namespace std;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>='0'&&jp<='9')
        {
            out=out*10+jp-'0';
            jp=getchar();
        }
    return out*fh;
}
const int P=1e9+7;
const int MAXN=1e6+10;
inline ll add(ll a,ll b)
{
    return (a+b)%P;
}
inline ll mul(ll a,ll b)
{
    return (a*b)%P;
}
inline ll sub(ll a,ll b)
{
    return (a-b)%P<0? (a-b)%P+P : (a-b)%P;
}
inline ll fpow(ll a,ll b)
{
    ll res=1;
    while(b)
        {
            if(b&1)
                res=mul(a,res);
            b>>=1;
            a=mul(a,a); 
        }
    return res;
}
inline ll inv(ll x)
{
    return fpow(x,P-2);
}
struct SegTree{
    struct node{
        ll val,f;
        int l,r;
    }Tree[MAXN<<2];
    inline void pushup(int o)
        {
            root.val=add(lson.val,rson.val);
        }
    void BuildTree(int o,int l,int r,int v[])
        {
            root.l=l,root.r=r;
            root.f=0;
            if(l==r)
                {
                    root.val=1ll*v[l];
                    return;
                }
            int mid=(l+r)>>1;
            BuildTree(o<<1,l,mid,v);
            BuildTree(o<<1|1,mid+1,r,v);
            pushup(o);
        }
        void Modifiy(int o,ll c)
            {
                root.f=add(root.f,c);
                root.val=add(root.val,mul(c,root.r-root.l+1));
            }
        void pushdown(int o)
            {
                if(root.f)
                    {
                        Modifiy(o<<1,root.f);
                        Modifiy(o<<1|1,root.f);
                        root.f=0;
                    }
            }
        void update_seg(int o,int L,int R,ll c)
            {
                int l=root.l,r=root.r;
                if(r<L || l>R)
                    return;
                if(L<=l && r<=R)
                    {
                        Modifiy(o,c);
                        return;
                    }
                pushdown(o);
                int mid=(l+r)>>1;
                if(L<=mid)
                    update_seg(o<<1,L,R,c);
                if(R>mid)
                    update_seg(o<<1|1,L,R,c);
                pushup(o);
            }
        void update_point(int o,int pos,ll c)
            {
                int l=root.l,r=root.r;
                if(r<pos || l>pos)
                    return;
                if(l==pos && r==pos)
                    {
                        root.val=add(root.val,c);
                        return;
                    }
                int mid=(l+r)>>1;
                if(pos<=mid)
                    update_point(o<<1,pos,c);
                if(pos>mid)
                    update_point(o<<1|1,pos,c);
                pushup(o);
            }
        ll Query(int o,int L,int R)
            {
                int l=root.l,r=root.r;
                if(r<L || l>R)
                    return 0;
                if(L<=l && r<=R)    
                    return root.val;
                ll res=0;
                pushdown(o);
                int mid=(l+r)>>1;
                if(L<=mid)
                    res=add(res,Query(o<<1,L,R));
                if(R>mid)
                    res=add(res,Query(o<<1|1,L,R));
                return res;
            }
}Tmax,Tmin;
int n,m;
int c[MAXN],del[MAXN>>1];
ll fac[MAXN],invfac[MAXN];
inline ll Catalan(int x)
{
    return mul(mul(fac[2*x],invfac[x]),invfac[x+1]);
}
int main()
{
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=2*n;++i)
        c[i]=read();
    for(int i=1;i<=n;++i)
        del[i]=c[2*i]-c[2*i-1];
    fac[1]=invfac[1]=1;
    for(int i=2;i<=2*n;++i)
        {
            fac[i]=mul(fac[i-1],i);
            invfac[i]=inv(fac[i]);
        }
//  for(int i=1;i<=10;++i)
//      printf("%lld,",Catalan(i));
    Tmax.BuildTree(1,1,2*n,c);
//  cerr<<"1"<<endl;
    Tmin.BuildTree(1,1,n,del);
    while(m--)
        {
            int opt=read();
            if(opt==0)
                {
                    int L=read(),R=read(),val=read();
                    Tmax.update_seg(1,L,R,1ll*val);
                    if(L%2==0)
                        {
                            Tmin.update_point(1,L>>1,val);
                            Tmin.update_point(1,(R+1)>>1,-val);
                        }
                }
            else
                {
                    int L=read(),R=read();
                    int Mid=(L+R)>>1;
                    ll maxans=sub(Tmax.Query(1,Mid+1,R),Tmax.Query(1,L,Mid));
                    printf("%lld ",maxans);
                    ll minans;
                    if(L&1)
                        {
                            minans=Tmin.Query(1,(L+1)>>1,R>>1);
                        }
                    else
                        {
                            int nl=L+1,nr=R-1;
                            if(nl>0 && nl<=2*n && nr>0 && nr<=2*n && nl<nr)
                                minans=Tmin.Query(1,(nl+1)>>1,nr>>1);
                            else
                                minans=0;
                            minans=mul(minans,-1);
                            minans=add(minans,Tmax.Query(1,R,R));
                            minans=sub(minans,Tmax.Query(1,L,L));
                        }
                    printf("%lld ",minans);
                    int len=(R-L+1)>>1;
                    printf("%lld\n",Catalan(len));
                }
        }   
    return 0;
}

T3

資料範圍 \(l,r,k \leq 1e18\),\(k \geq 2\).

接手T3時,因為上個題的sb除錯,只剩10分鐘了...

感覺這題可能要GG,但好在此題暴力十分好寫(絕對比T2暴力好寫幾個數量級) ,怒敲5分鐘暴力,毅然提交...

弱智暴力就沒啥必要貼程式碼了吧...

然後我的T1亂搞竟然就A了,出題人大概也沒想到卡我這亂搞操作...220pts,爆踩std10分,std的lld出鍋了,驚險拿下第一次rk1....