湖南测试 1

思路:二分答案水过

 

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100100
using namespace std;
int n,m,tx,ty,ans;
int cntx[MAXN],cnty[MAXN];
struct nond{
    int x,y,d;
    double k;
}cnt[MAXN];
bool check(int mid){
    double dy=cnt[mid].k*tx+cnt[mid].d;
    if(dy<=ty)    return true;
    else return false;
}
int main(){
    freopen("geometry.in","r",stdin);
    freopen("geometry.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&cntx[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&cnty[i]);
    sort(cntx+1,cntx+1+n);
    sort(cnty+1,cnty+1+n);
    for(int i=1;i<=n;i++){
        cnt[i].x=cntx[i];
        cnt[i].y=cnty[i];
        cnt[i].k=-1*(cnty[i]*1.0/cntx[i]*1.0);
        cnt[i].d=cnty[i];
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&tx,&ty);
        int l=0,r=n,mid;
        while(l<=r){
            mid=(l+r)/2;
            if(check(mid))    l=mid+1,ans=mid;
            else r=mid-1;
        }
        cout<<ans<<endl;
    }
}

思路:贪心,水了45分,据说大佬的贪心可以水85分的。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 50
using namespace std;
int t,sum,ans;
int need[MAXN],people[MAXN],vis[MAXN];
int main(){
    freopen("cashier.in","r",stdin);
    freopen("cashier.out","w",stdout);
    scanf("%d",&t);
    while(t--){
        ans=0;
        bool flag=0;
        memset(vis,0,sizeof(vis));
        memset(need,0,sizeof(need));
        memset(people,0,sizeof(people));
        for(int i=1;i<=24;i++){ scanf("%d",&need[i]); need[24+i]=need[i]; }    
        for(int i=1;i<=24;i++){ scanf("%d",&people[i]); people[24+i]=people[i]; }    
        for(int i=25;i<=48;i++){
            if(need[i]!=0){
                sum=0;
                for(int j=i-7;j<=i;j++)
                    if(vis[j]!=0)    sum+=vis[j];
                if(sum>=need[i])    continue;
                if(i-7>=25){
                    for(int j=i;j>=i-7;j--)
                        if(vis[j]!=people[j]&&people[j]!=0){
                            if(sum==need[i])    break;
                            if(sum+people[j]-vis[j]<=need[i])    sum+=people[j]-vis[j],vis[j]=people[j];
                            else if(sum+people[j]-vis[j]>need[i])    vis[j]=need[i]-sum,sum=need[i];
                        }
                }
                else{
                    for(int j=i-7;j<=i;j++)
                        if(vis[j]!=people[j]&&people[j]!=0){
                            if(sum==need[i])    break;
                            if(sum+people[j]-vis[j]<=need[i]){
                                sum+=people[j]-vis[j],vis[j]=people[j];
                                if(j<=24)    sum+=people[j]-vis[j],vis[j+24]=people[j];    
                            }    
                            else if(sum+people[j]-vis[j]>need[i]){
                                vis[j]=need[i]-sum,sum=need[i];
                                if(j<=24)    vis[j+24]=need[i]-sum,sum=need[i];
                            }
                        }
                }
                if(sum<need[i]){ cout<<"-1";flag=1;break; }
            }
        }
        for(int i=25;i<=48;i++)    ans+=vis[i];
        if(!flag)    cout<<ans<<endl;
    }
}
/*
1
0 0 0 0 0 0 0 0 4 5 2 2 2 6 3 2 4 3 2 1 1 2 1 0
1 1 1 0 0 0 1 1 3 1 1 0 0 2 0 0 0 3 1 1 1 0 0 2
1
0 1 0 0 0 0 0 0 2 2 1 5 2 0 3 1 1 4 1 4 2 6 3 3
1 1 1 0 1 0 0 0 0 1 3 2 0 0 4 0 3 0 1 0 0 2 0 0
*/

正解思路:查分约束

记录前缀和sum[i](前缀和是指最终应该得到的答案的前缀和)

当i>=8时 应该满足条件:s[i]-s[i-8]>=a[i];

            0<=s[i]-s[i-1]<=b[i];

当i<  8时 应该满足条件:s[23]-s[16+i]+s[i]>=a[i];(下标从0开始)

但是第3个式子并不满足差分约束的性质。

我们可以发现第三个式子中的s[23]具有单调性,所以可以从小到大枚举s[23]是几,第一个符合条件的一定是最小的(s[23](也就是最终的答案是几),二分s[23]的值也可以),然后就可以转为符合差分约束的式子:

  s[i]-s[16+i]>=a[i]-s[23];

然后spfa判负环,跑差分约束即可。

#include<queue> 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 50
using namespace std;
queue<int>que;
int t,tot,ans;
int a[MAXN],b[MAXN];
int dis[MAXN],vis[MAXN];
int to[MAXN*2],cap[MAXN*2],net[MAXN*2],head[MAXN*2];
void add(int u,int v,int w){
    to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot;
}
bool spfa(int s){
    memset(vis,0,sizeof(vis));
    memset(dis,-0x7f7f7f7f,sizeof(dis));
    while(!que.empty())    que.pop();
    que.push(s);
    dis[s]=0;vis[s]=1;
    while(!que.empty()){
        int now=que.front();
        que.pop();
        vis[now]=0;
        if(dis[now]>1000)    return false;
        for(int i=head[now];i;i=net[i])
            if(dis[to[i]]<dis[now]+cap[i]){
                dis[to[i]]=dis[now]+cap[i];
                if(!vis[to[i]]){
                    vis[to[i]]=1;
                    que.push(to[i]);
                }
            }
    }
    return true;
}
bool judge(int ans){
    memset(head,0,sizeof(head));tot=0;
    for(int i=9;i<=24;i++)    add(i-8,i,a[i]);
    for(int i=1;i<=8;i++)    add(i+16,i,a[i]-ans);
    for(int i=1;i<=24;i++)    add(i-1,i,0);
    for(int i=1;i<=24;i++)    add(i,i-1,-b[i]);
    add(0,24,ans);
    add(24,0,-ans);
    return spfa(0);
}
int main(){
    freopen("cashier.in","r",stdin);
    freopen("cashier.out","w",stdout);
    scanf("%d",&t);
    while(t--){
        for(int i=1;i<=24;i++)    scanf("%d",&a[i]);
        for(int i=1;i<=24;i++)    scanf("%d",&b[i]);
        ans=0;
        while(1){
            if(++ans>1000){
                ans=-1;
                break;
            }
            if(judge(ans))    break;
        }
        cout<<ans<<endl;
    }
}
/*
1
0 0 0 0 0 0 0 0 2 2 1 5 2 0 3 1 1 4 1 4 2 6 3 3
1 1 1 0 1 0 0 0 0 1 3 2 0 0 4 0 3 0 1 0 0 2 0 0
*/

 

 

思路:

 自己写的80分暴力的线段树,然并卵,爆零了,QwQ求大佬找茬...

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN  50100
#define mod 1000000007
using namespace std;
int n,m;
struct nond{
    int l,r;
    long long sum;
    long long flag1,flag2;
}tree[MAXN*4];
void up(int now){
    tree[now].sum=(tree[now*2].sum+tree[now*2+1].sum)%mod;
}
void build(int now,int l,int r){
    tree[now].l=l;
    tree[now].r=r;
    tree[now].flag2=1;
    if(tree[now].l==tree[now].r){
        scanf("%d",&tree[now].sum);
        return ;
    }
    int mid=(tree[now].l+tree[now].r)/2;
    build(now*2,l,mid);
    build(now*2+1,mid+1,r);
    up(now);
}
void down(int now){
    tree[now*2].flag2=(tree[now].flag2*tree[now*2].flag2)%mod;
    tree[now*2+1].flag2=(tree[now].flag2*tree[now*2+1].flag2)%mod;
    tree[now*2].flag1=(tree[now].flag2*tree[now*2].flag1%mod+tree[now].flag1)%mod;
    tree[now*2+1].flag1=(tree[now].flag2*tree[now*2+1].flag1%mod+tree[now].flag1)%mod;
    tree[now*2].sum=(tree[now].flag2*tree[now*2].sum%mod+tree[now].flag1*(tree[now*2].r-tree[now*2].l+1)%mod)%mod;
    tree[now*2+1].sum=(tree[now].flag2*tree[now*2+1].sum%mod+tree[now].flag1*(tree[now*2+1].r-tree[now*2+1].l+1)%mod)%mod;
    tree[now].flag2=1;
    tree[now].flag1=0;
}
void change1(int now,int l,int r,int k){
    if(tree[now].l==l&&tree[now].r==r){
        tree[now].flag1+=k;
        tree[now].sum+=1ll*(tree[now].r-tree[now].l+1)*k;
        return ;
    }
    down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)    change1(now*2,l,r,k);
    else if(l>mid)    change1(now*2+1,l,r,k);
    else{
        change1(now*2,l,mid,k);
        change1(now*2+1,mid+1,r,k);
    }
    up(now);
}
void change2(int now,int l,int r,int v){
    if(tree[now].l==l&&tree[now].r==r){
        tree[now].flag2=(tree[now].flag2*v)%mod;
        tree[now].flag1=(tree[now].flag1*v)%mod;
        tree[now].sum=(tree[now].sum*v)%mod;
        return ;
    }
    down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)    change2(now*2,l,r,v);
    else if(l>mid)    change2(now*2+1,l,r,v);
    else{
        change2(now*2,l,mid,v);
        change2(now*2+1,mid+1,r,v);
    }
    up(now);
}
long long query(int now,int l,int r){
    if(tree[now].l==l&&tree[now].r==r)
        return tree[now].sum%mod;
    down(now);
    int mid=(tree[now].l+tree[now].r)/2;
    if(r<=mid)    return query(now*2,l,r);
    else if(l>mid)    return query(now*2+1,l,r);
    else return query(now*2,l,mid)+query(now*2+1,mid+1,r);
}
int main(){
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        int a,b,c,d;
        scanf("%d%d%d",&a,&b,&c);
        if(a==1){
            scanf("%d",&d);
            change1(1,b,c,d);
        }
        if(a==2)    change2(1,b,c,-1);
        if(a==3){
            scanf("%d",&d);
            if(d==1){
                long long ans=0;
                ans=query(1,b,c);
                if(ans<0)    ans+=mod;
                cout<<ans<<endl;
            }    
            if(d==2){
                long long ans=0;
                for(int i=b;i<c;i++)
                    ans=(ans+query(1,i+1,c)*query(1,i,i))%mod;
                if(ans<0)    ans+=mod;
                cout<<ans<<endl;
            }
        }
    }
}
/*
10 9
3 6 7 4 6 1 6 7 2 6
3 5 7 3
1 1 7 -9
1 2 3 5
3 2 6 1
2 5 8
3 5 7 3
2 2 3
3 1 10 2
3 1 2 2
*/
爆0的线段树

线段树

部分分可以dp f[i][j]表示前i个数选了j个的答案

f[i][j]=f[i-1][j]+f[i-1][j-1]*a[i] (i选不选)

k=1时线段树区间求和区间修改,我只会这个....

 

线段树区间合并操作。

k比较小,所以线段树每个节点维护一个区间答案记为f[i]

考虑一段区间i,左边取j个右边就取i-j个 答案是每个方案的左边乘右边的和。

就是i左儿子f[j]和右边的f[i-j] 所以f[i]=Σ(j=0~i) lc f[j]*rc f[i-j]

考虑取反操作,i是奇数就取反,偶数无影响(因为是相乘)

考虑区间加, 开始f[i] 是 a1*a2……an  后来是(a1+c)*(a2+c)……(an+c)

考虑类似二项式定理,当上述a1~an  n个方案如果取了j个了,分别为al1,al2……alj

那考虑最后答案,如果已经选了j个方案是(al1+c)(al2+c)……(alj+c)再还能选i-j个 最后答案是C(len-i,i-j)*f[j]*c^(i-j)

复杂度 O(k^2*nlogn)

 

只懂思路,代码....果断粘std

#include <cstdio>
#include <cstdlib>
#define MOD 1000000007
#define N 100005
typedef long long LL;
using namespace std;
struct Node
{
    LL f[11];
} node[N * 4];
LL a[N], lazy1[N * 4];
bool lazy2[N * 4];
LL C[N][11];
 
Node merge(Node lc, Node rc)
{
    Node o;
    o.f[0] = 1;
    for (int i = 1; i <= 10; i++)
    {
        o.f[i] = 0;
        for (int j = 0; j <= i; j++)
            o.f[i] = (o.f[i] + lc.f[j] * rc.f[i - j] % MOD) % MOD;
    }
    return o;
}
 
void build(int o, int l, int r)
{
    if (l == r)
    {
        for (int i = 0; i <= 10; i++) node[o].f[i] = 0;
        node[o].f[0] = 1;
        node[o].f[1] = (a[l] % MOD + MOD) % MOD;
        return ;
    }
    int mid = (l + r) >> 1;
    build(o * 2, l, mid);
    build(o * 2 + 1, mid + 1, r);
    node[o] = merge(node[o * 2], node[o * 2 + 1]);
    return ;
}
 
void update1(int o, int l, int r, int c)
{
    int len = r - l + 1;
    LL ff[11];
    for (int i = 0; i <= 10; i++) ff[i] = node[o].f[i];
    for (int i = 1; i <= 10; i++)
    {
        node[o].f[i] = 0;
        LL t = 1;
        for (int j = 0; j <= i; j++)
        {
            LL tmp = ff[i - j] * C[len - (i - j)][j] % MOD * t % MOD;
            node[o].f[i] = (node[o].f[i] + tmp) % MOD;
            t = t * c % MOD;
        }
    }
    return ;
}
 
void push_down(int o, int l, int r)
{
    int mid = (l + r) >> 1;
    if (lazy1[o])
    {
        if (lazy2[o * 2])
            lazy1[o * 2] = (lazy1[o * 2] + MOD - lazy1[o]) % MOD;
        else
            lazy1[o * 2] = (lazy1[o * 2] + lazy1[o]) % MOD;
        if (lazy2[o * 2 + 1])
            lazy1[o * 2 + 1] = (lazy1[o * 2 + 1] + MOD - lazy1[o]) % MOD;
        else
            lazy1[o * 2 + 1] = (lazy1[o * 2 + 1] + lazy1[o]) % MOD;
        update1(o * 2, l, mid, lazy1[o]);
        update1(o * 2 + 1, mid + 1, r, lazy1[o]);
        lazy1[o] = 0;
    }
    if (lazy2[o])
    {
        lazy2[o * 2] ^= 1;
        lazy2[o * 2 + 1] ^= 1;
        for (int j = 1; j <= 10; j += 2)
        {
            node[o * 2].f[j] = MOD - node[o * 2].f[j];
            node[o * 2 + 1].f[j] = MOD - node[o * 2 + 1].f[j];
        }
        lazy2[o] = 0;
    }
}
 
void modify1(int o, int l, int r, int ll, int rr, int c)
{
    if (ll <= l && rr >= r)
    {
        if (lazy2[o]) lazy1[o] = (lazy1[o] + MOD - c) % MOD;
        else lazy1[o] = (lazy1[o] + c) % MOD;
        update1(o, l, r, c);
        return ;
    }
    int mid = (l + r) >> 1;
    push_down(o, l, r);
    if (ll <= mid) modify1(o * 2, l, mid, ll, rr, c);
    if (rr > mid) modify1(o * 2 + 1, mid + 1, r, ll, rr, c);
    node[o] = merge(node[o * 2], node[o * 2 + 1]);
    return ;
}
 
void modify2(int o, int l, int r, int ll, int rr)
{
    if (ll <= l && rr >= r)
    {
        for (int i = 1; i <= 10; i += 2) node[o].f[i] = MOD - node[o].f[i];
        lazy2[o] ^= 1;
        return ;
    }
    int mid = (l + r) >> 1;
    push_down(o, l, r);
    if (ll <= mid) modify2(o * 2, l, mid, ll, rr);
    if (rr > mid) modify2(o * 2 + 1, mid + 1, r, ll, rr);
    node[o] = merge(node[o * 2], node[o * 2 + 1]);
    return ;
}
 
Node query(int o, int l, int r, int ll, int rr)
{
    if (ll <= l && rr >= r)
        return node[o];
    int mid = (l + r) >> 1;
    push_down(o, l, r);
    if (rr <= mid) return query(o * 2, l, mid, ll, rr);
    if (ll > mid) return query(o * 2 + 1, mid + 1, r, ll, rr);
    Node lc = query(o * 2, l, mid, ll, rr);
    Node rc = query(o * 2 + 1, mid + 1, r, ll, rr);
    return merge(lc, rc);
}
 
int main(int argc, char ** argv)
{
    freopen("game.in", "r", stdin);
    freopen("game.out", "w", stdout);
    int n, m;
    scanf("%d %d", &n, &m);
    C[0][0] = 1;
    for (int i = 1; i <= n; i++)
    {
        C[i][0] = 1;
        for (int j = 1; j <= 10; j++)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
    }
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    build(1, 1, n);
    for (int i = 1; i <= m; i++)
    {
 
        int l, r, opt;
        scanf("%d%d%d",&opt, &l, &r);
        if (opt == 1)
        {
            int c;
            scanf("%d", &c);
            c = (c % MOD + MOD) % MOD;
            modify1(1, 1, n, l, r, c);
        }
        else if (opt == 2)
        {
            modify2(1, 1, n, l, r);
        }
        else
        {
            int k;
            scanf("%d", &k);
            Node o = query(1, 1, n, l, r);
            printf("%d\n", o.f[k] % MOD);
        }
    }
    return 0;
}

 

posted @ 2017-10-16 16:56  一蓑烟雨任生平  阅读(229)  评论(0编辑  收藏  举报