牛客网暑期ACM多校训练营(第三场)

牛客网暑期ACM多校训练营(第三场)


A. PACM Team

01背包,输出方案,用bool存每种状态下用的哪一个物品,卡内存。官方题解上,说用char或者short就行了。还有一种做法是把用的物品压成一个int。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
typedef long long ll;
typedef long double LD;
using namespace std;
int n,p[37],a[37],c[37],m[37],g[37],A,C,M,P,ans = 0;
int dp[37][37][37][37];
bool usd[37][37][37][37][37];
int v[40],cnt=0,vis[40];
int main() {
    int tp=0,ta=0,tc=0,tm=0,tmp=0;
    scanf("%d",&n);
    rep(i,0,n-1) {
        scanf("%d%d%d%d%d",&p[i],&a[i],&c[i],&m[i],&g[i]);
    }
    scanf("%d%d%d%d",&P,&A,&C,&M);
    dp[0][0][0][0] = tmp;
    rep(i,0,n-1) {
        per(ip,P,p[i])per(ia,A,a[i])per(ic,C,c[i])per(im,M,m[i]) {
                int t = 0,t2 = dp[ip-p[i]][ia-a[i]][ic-c[i]][im-m[i]] + g[i];
                t = dp[ip][ia][ic][im];
                if(t <= t2) {
                    dp[ip][ia][ic][im] = t2;
                    usd[ip][ia][ic][im][i] = 1;
                }
        }
    }
    tp = P; ta = A; tc = C; tm = M;
    per(i,n-1,0) if(tp>=0&&ta>=0&&tc>=0&&tm>=0) {
        if(usd[tp][ta][tc][tm][i]) {
            v[++cnt]=i;
            tp-=p[i];
            ta-=a[i];
            tc-=c[i];
            tm-=m[i];
        }
    }
    sort(v+1,v+1+cnt);
    printf("%d\n",cnt);int f=0;
    if(cnt) {
        for(int i=1;i<=cnt;++i) {
            if(f)printf(" ");f=1;
            printf("%d",v[i]);
        }puts("");
    }
    return 0;
}

C. Shuffle Cards

每次把中间一段数字移到开头。学习了rope的用法。然后写了个块链。。。t到爆炸。

rope:
push_back(x);//在末尾添加x
insert(pos,x);//在pos插入x,自然支持整个char数组的一次插入
erase(pos,x);//从pos开始删除x个
copy(pos,len,x);//从pos开始长度为len用x代替
replace(pos,x);//从pos开始换成x
substr(pos,x);//提取pos开始x个
at(x)/[x];//访问第x个元素

rope做法:

#include <bits/stdc++.h>
#include <ext/rope>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
typedef long long ll;
const int N = 1e6 + 7;
using namespace std;
using namespace __gnu_cxx;
int n,m;
rope<int> s;
int main() {
    scanf("%d%d",&n,&m);
    rep(i,1,n) s.pb(i);
    rep(i,1,m) {int p,x;
        scanf("%d%d",&p,&x);
        s = s.substr(p-1,x) + s.substr(0,p-1) + s.substr(p+x-1,n-(p+x-1));
    }
    int f=0;
    rep(i,0,n-1) {
        if(f)printf(" ");f=1;
        printf("%d",s[i]);
    }puts("");
    return 0;
}

块链做法:

//listblock TLE

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
typedef long long ll;
const int N = 300010;
const int M = 1000 + 7;
using namespace std;
int n,m,B,num,hd;
struct listBlock{
    vector<int> s;
    int nxt,pre;
    void init(){s.clear();nxt=pre=0;}
    void ins(int x) {s.pb(x);}
}block[N];
void init(int s[]) {
    B = sqrt(n);
    num = n/B; if(n%B)++num;
    hd=0;
    block[hd].nxt = 1;
    rep(i,1,num) block[i].init(),block[i].nxt=i+1,block[i].pre=i-1;
    block[num].nxt = -1;
    rep(i,0,n-1) block[i/B+1].ins(s[i]);
}
void split(int x,int p) {//(l[x],p)(p+1,r[x])
    if(p==(int)block[x].s.size()-1)return;
    int n = (int)block[x].s.size();
    listBlock tmp = block[x];

    block[x].init();
    rep(i,0,p)block[x].ins(tmp.s[i]);
    block[x].pre = tmp.pre;
    block[x].nxt = num+1;

    ++num; block[num].init();
    rep(i,p+1,n-1)block[num].ins(tmp.s[i]);
    block[num].pre = x;
    block[num].nxt = tmp.nxt;

    block[tmp.pre].nxt = x;
    block[tmp.nxt].pre = num;

    tmp.init();
}
int fd(int x,int &sum) {
    sum=0;
    for(int i=hd;i!=-1;i=block[i].nxt) {
        sum+=(int)block[i].s.size();
        if(sum>=x) return i;
    }
    return 0;
}
void pt(int x) {
    printf("%d block:\n",x);
    printf("sz: %d\n",block[x].s.size());
    rep(i,0,block[x].s.size()-1)printf("%d ",block[x].s[i]);puts("");
    printf("nxt: %d\n",block[x].nxt);
    printf("pre: %d\n",block[x].pre);
}
int merge(int x,int y) {
    if(x==y)return x;
    if(x==-1||y==-1||x==hd||y==hd)return x;
    rep(i,0,(int)block[y].s.size()-1)block[x].ins(block[y].s[i]);
    block[x].nxt = block[y].nxt;
    block[block[y].nxt].pre = x;
    block[y].init();
    return x;
}
void adpt() {
    for(int i=hd;i!=-1;i=block[i].nxt) {
        if(i!=hd&&block[i].nxt!=-1&&(int)block[i].s.size()+(int)block[block[i].nxt].s.size() <= B) {
            i = merge(i,block[i].nxt);
        }
    }
}
void solve(int l,int r) {
    int suml=0,sumr=0;
    int pl = fd(l,suml);
    int pr = fd(r,sumr);
    if(l>suml-(int)block[pl].s.size()+1) split(pl,l-(suml-(int)block[pl].s.size())-1-1);
    if(r<sumr) split(pr,r-(sumr-(int)block[pr].s.size())-1);

    pl = fd(l,suml);
    pr = fd(r,sumr);

    block[block[pl].pre].nxt = block[pr].nxt;
    block[block[pr].nxt].pre = block[pl].pre;
    block[block[hd].nxt].pre = pr;
    block[pl].pre = hd;
    block[pr].nxt = block[hd].nxt;
    block[hd].nxt = pl;
}
int s[N];
int main() {
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i) s[i]=i+1;
    init(s);

    rep(i,1,m) {int l,r,p;
        scanf("%d%d",&l,&p);
        r = l+p-1;
        solve(l,r);
        adpt();
    }
    int f=0;
    for(int i=hd;~i;i=block[i].nxt) {
        if(i!=hd) {
            for(int j=0;j<(int)block[i].s.size();++j) {
                if(f)printf(" ");f=1;
                printf("%d",block[i].s[j]);
            }
        }
    }puts("");
    return 0;
}

E. Sort String

这句话脑抽读不懂。。。就查了下中文题意

For each i in [0,|S|-1], let Si be the substring of S starting from i-th character to the end followed by the substring of first i characters of S. Index of string starts from 0.

就是我把这个串循环移位,把相同的分在一组输出。
做法就是kmp找循环节,如果这个串不是周期串,则每个位置都不在一组,否则就把一个周期拆开即可。难点真的在读题。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
typedef long long ll;
const int N = 1e6 + 7;
using namespace std;
int len,nxt[N];
char s[N];
void getnxt() {
    int i=0,j;
    j=nxt[0]=-1;
    while(i<len) {
        while(j!=-1&&s[i]!=s[j])j=nxt[j];
        nxt[++i]=++j;
    }
}
int main() {
    scanf(" %s",s);
    len = strlen(s);
    getnxt();
    int t = len - nxt[len];
    if(len%t) {
        printf("%d\n",len);
        rep(i,0,len-1)printf("1 %d\n",i);
    }
    else {
        printf("%d\n",t);
        rep(i,0,t-1) {
            printf("%d",len/t);
            for(int j=i;j<len;j+=t)printf(" %d",j);puts("");
        }
    }
    return 0;
}

H. Diff-prime Pairs

先保证i小于j,打了个表发现,对于素数j,与他配对的就是它比他小的所有素数,对于合数,与他配对的就是它的所有素因子,的配对之和。于是考虑,每个素数x对答案的贡献,就是能整除x的数乘上比他小的素数的个数,最后乘2


#include <bits/stdc++.h>
typedef long long ll;
const int N = 10000000;
using namespace std;
ll ans=0,num=0;
int n,phi[N+1],notp[N+1],p[N+1];
void init() {
    notp[1]=1;
    for(int i=2; i<=n; i++) {
        if(!notp[i]) p[++p[0]] = i;
        for(int j=1; j<=p[0] && i*p[j]<=n; j++) {
            notp[i*p[j]] = 1;
            if(i%p[j] == 0) break;
        }
    }
}

int main() {
    scanf("%d",&n);
    init();
    for(int i=1;i<=n;++i) if(!notp[i]){
        ans += (n/i)*num;
        ++num;
    }
    printf("%lld\n",ans*2LL);
    return 0;
}

I. Expected Size of Random Convex Hull

一开始读错题,拿pick定理搞了半天。。。因为n十分的小,于是直接随机然后取平均。然后写了锐角坐标系中的随机取点。WA了之后,发现答案好像与三角形的形状无关,感性思考一下,任何一种点的分布,都可以通过线性变换成为另一个三角坐标系中的点。所以答案与n相关,那就可以打表了。三角形直接取最简单的沿xy轴的等腰直角三角形,让边长尽可能长。然后,我的写法每种n随机了1e8次,精度才够。

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
typedef long long ll;
typedef long double LD;
const int lim = 100000005;
using namespace std;
struct point{
    double x,y;
    point operator + (const point a)const {
        point t;
        t.x = a.x+x, t.y = a.y+y;
        return t;
    }
    point operator - (const point a)const {
        point t;
        t.x = x - a.x, t.y = y - a.y;
        return t;
    }
}p[3],v[12];
int n,cnt;
point mkp() {
    point C;
    C.x = ((double)rand())/RAND_MAX;
    C.y = ((double)rand())/RAND_MAX;
    return C;
}
struct Line_segment {
    point s,e;
    Line_segment() {}
    Line_segment(point a,point b):s(a),e(b) {}
};
double multiply(point sp,point  ep,point op) {
    return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}

bool cmp1(point a,point b) {
    if(a.x == b.x) return a.y < b.y;
    return a.x < b.x;
}
point res[22];
int graham(point pnt[],int n,point res[]) {
    sort(pnt,pnt+n,cmp1);
    int m=0, k;
    for(int i = 0; i < n; i++) {
        while(m>1 && multiply(res[m-1],pnt[i],res[m-2])<=0) m--;
        res[m++]=pnt[i];
    }
    k = m;
    for(int i = n-2; i >= 0; i--) {
        while(m>k && multiply(res[m-1],pnt[i],res[m-2])<=0) m--;
        res[m++]=pnt[i];
    }
    if(n > 1) m--;
    return m;
}
void getpoint() {
    for(int i=0;i<n;++i) {
        point p1 = mkp();
        if(p1.x<p1.y)swap(p1.x,p1.y);
        v[i]=p1;
    }
}
int tubao() {
    return graham(v,n,res);
}
double a[]={0,0,0,3.000000,3.6667248067,4.1667674917,4.5667089017,4.9000191650,5.1856561607,5.4356834882,5.6579956371};
int main() {
    //freopen("out.txt","w",stdout);

    rep(i,0,2)scanf("%lf%lf",&p[i].x,&p[i].y);
    scanf("%d",&n);
//    for(n=3;n<=10;++n) {
//        srand(time(0));
//        LD ans = 0;
//        rep(ti,1,lim) {
//            getpoint();
//            int tmp = tubao();
//            ans += tmp;
//        }
//        printf("%.10f\n",(double)ans/lim);
//    }
    printf("%.10f\n",a[n]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/RRRR-wys/p/9379778.html
今日推荐