繁华模拟赛day8 牛栏

/*
标称并没有用到题解中提到的那种奇妙的性质,我们可以证明,正常从1开始走的话,需要T次,如何使这个次数减小?题解中提到一个办法,有一步小于n/t,我们考虑这一步,如果把它匀到左右两步中,则可以减小,就根据这个性质来优化
next函数的部分,我当时用了一个倍增法,题解用了一个并查集,倍增比较直观,然而并查集更为巧妙
*/
//my code
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
const int maxn = 600500;
int n,q,cnt,ct[maxn];
ll a[maxn],sum[maxn],ans;
ll read(){
    char ch=getchar();
    ll x=0,f=1;
    while(!(ch>=‘0‘&&ch<=‘9‘)){if(ch==‘-‘)f=-1;ch=getchar();};
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+(ch-‘0‘);ch=getchar();};
    return x*f;
}
ll greedy(int u,ll t){
    ll tot = 0,tmp = 0;
    ll j,lg,tst,nt;
    for(int i = 1;i <= n;i++){
        tmp++;
        if(a[u] + a[u+1] > t || i == n){

        }else{
            lg = 0;
            j = 1;
            tot = 0;
            while(lg>=0){
                if(u+j<=n){
                    tst = sum[u+j]-sum[u-1];
                    nt = u + j;
                }
                else{
                    tst = sum[n] - sum[u-1] + sum[u+j-n];
                    nt = u + j - n;
                }
                if(tot + tst <= t){
                    i += j;
                    tot += tst - a[nt];
                    u = nt;
                    lg++;
                    j <<= 1;
                }else{
                    lg--;
                    j >>= 1;
                }
            }
        }
        u++;
        if(u > n) u = 1;
        if(tmp >= ans) break;
    }
    return tmp;
}
void work(ll t){
    cnt = 0;
    ans = maxn;
    ct[++cnt] = 1;
    ll sum = a[1];
    for(int i = n;i > 1;i--){
        sum += a[i];
        if(sum > t) break;
        ct[++cnt] = i;
    }
    for(int i = 1;i <= cnt;i++){
        ans = min(ans,greedy(ct[i],t));
    }
    cout<<ans<<endl;
}
int main(){
    freopen("stall.in","r",stdin);
    freopen("stall.out","w",stdout);
    n = read();
    q = read();
    for(int i = 1;i <= n;i++){
        a[i] = read();
        sum[i] = sum[i-1] + a[i];
    }
    ll b;
    for(int i = 1;i <= q;i++){
        b = read();
        work(b);
    }
    return 0;
}
//std
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#define INF 1000000000
#define N 2000005
#define fi first
#define se second
#define debug(x) cout<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
LL a[N],s[N];
int to[N],fa[N],d[N];
int findr(int x)
{
    if(fa[x]==x)
        return x;
    else
    {
        int t=fa[x];
        fa[x]=findr(fa[x]);
        d[x]=d[x]+d[t];
        return fa[x];
    }
}

void Union(int x,int y)
{
    fa[x]=y;
    d[x]=1;
}

int main()
{
    int size = 256 << 20; // 256MB
    char *p = (char*)malloc(size) + size;
    __asm__("movl %0, %%esp\n" :: "r"(p));
    freopen("stall.in","r",stdin);
    freopen("stall.out","w",stdout);
    cin>>n>>q;
    for(i=1;i<=n;i++)
        scanf("%I64d",&a[i]),a[i+n]=a[i];
    for(i=n*2;i;i--)
        s[i]=s[i+1]+a[i];
    while(q--)
    {
        ans=INF;
        cin>>m;
        memset(d,0,sizeof(d));
        for(i=1;i<=n;i++)
            fa[i]=i,fa[i+n]=i+n;
        for(j=n*2,i=n*2;i;i--)
        {
            while(s[i]-s[j+1]>m) j--;
            to[i]=j+1;
            //debug(to[i]);
        }
        //if(q==1) return 0;
        for(i=1;i<=n;i++)
        {
            j=findr(i);
            while(to[j]<i+n)
            {
                k=to[j];
                Union(j,k);
                j=findr(k);
            }
            findr(i);
            ans=min(ans,d[i]);
        }
        cout<<ans+1<<endl;
    }
    return 0;
}
// davidlee1999WTK 2015/
// srO myk Orz
//ios::sync_with_stdio(false);
时间: 2024-10-21 14:24:37

繁华模拟赛day8 牛栏的相关文章

繁华模拟赛day8 科技树

/* 贪心,很明显是越容易升级的越先升级 */ #include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 100050; int n,k,t,a[maxn],lv[maxn],ans; int read(){ char ch=getchar(); i

繁华模拟赛day8 字典序

/* 这个题要我们求一个字典序,字符串给出的顺序,会对字母的字典序前后相对顺序进行限定,如何用来表示这种限定,我们注意到这种一个之后接着一个,只有先输出他前面的才能输出他,很明显就是拓扑排序,最小方案只要优先队列随便搞一搞就行了 */ #include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<vect

[繁华模拟赛]Evensgn 剪树枝

Evensgn 剪树枝 题目 繁华中学有一棵苹果树.苹果树有 n 个节点(也就是苹果),n − 1 条边(也就 是树枝).调皮的 Evensgn 爬到苹果树上.他发现这棵苹果树上的苹果有两种:一 种是黑苹果,一种是红苹果.Evensgn 想要剪掉 k 条树枝,将整棵树分成 k + 1 个 部分.他想要保证每个部分里面有且仅有一个黑苹果.请问他一共有多少种剪树枝 的方案? INPUT 第一行一个数字 n,表示苹果树的节点(苹果)个数. 第二行一共 n − 1 个数字 p0, p1, p2, p3,

繁华模拟赛 Evensgn的债务

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #define ll int using namespace std; const int maxn = 1000005; ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(

繁华模拟赛 ljw分雕塑

/* 用f[i][k]表示考虑到第i个雕塑,分成k组,可不可行(这是一个bool类型的数组) 转移: f[i][k]=f[j][k-1],sum[i]-sum[j]合法 */ #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const int max_n = 2010;

繁华模拟赛 找十字架

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; int n; char s[205][205],cmd; int main(){ freopen("puzzle.in","r",stdin); freopen("puzzle

繁华模拟赛 Vincent的城堡

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll mod = 1000000007; ll n,k,c[20][20]; ll ansa,ansb,ans; void get_c(){ for(int i = 1;i

繁华模拟赛 Evensgn玩序列

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 5000; int n,a[maxn],b[maxn],c[maxn],rka[maxn],rkb[maxn],rkc[maxn]; bool visa[maxn],visb[maxn],vi

繁华模拟赛 ljw搭积木

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> using namespace std; const int maxn = 6005; int n,x[maxn]; int cmd,cnt,ans,max_x; int main(){ freopen("box.in","r"