10月集训test20

有几天没有写总结了,后面应该会补上之前的总结。
第一次全场爆零呵呵呵呵。。。。。。。。。
第一题错在了最后答案没有%mod再输出(最好从头到尾都%mod);
第二题大概是没有很好地把握时间复杂度;
第三题嘛。。我是真的不知道怎么WA了,大概是爆int了?
上题。

1.数列求和

理解题意并不难,就是将原数列的每一个子段内部相乘,每一个子段之间将相乘的积相加。不难看出(所以这里真的不难看出吗。。。为什么我就是没有看出。。。),考虑所有右端点为x的答案,可以发现答案为所有右端点为x-1的答案加1,再乘a。但是由于后面到了1e18的精度,所以用快速乘即可。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

int n;
long long p,ans,now;
long long x;

inline long long read()
{
    long long i=0;char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i;
}

inline long long ksc(long long x,long long y)
{
    long long ans=0,aa=x;
    while(y)                          //快速乘。
    {
        if(y&1)
            ans=(ans+aa)%p;
        aa=(aa+aa)%p,y>>=1;
    }
    return ans;
}

int main()
{
    //freopen("sum.in","r",stdin);
    //freopen("sum.out","w",stdout);

    n=read(),p=read();
    ans=0;now=0;
    for(int i=1;i<=n;i++)
    {
        x=read();
        now=ksc(now+1,x);
        ans=(ans+now)%p;
    }   

    printf("%lld\n",ans);
    return 0;
}

2.路径统计

可以看出,每一个连通块里面,都是一个环再加上环上的许许多多奇形怪状的树,不同的连通块则不能连通。环上点对答案的贡献很好写,然后就是树边,下方的子树与上方路径上的点和环上点的路径。
要缩点呐,dfs其实就是dijkstra的思想。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<vector>
using namespace std;

struct node
{
    int next,to,w;
}bian[500010];
const int p=1000000007;
int n,tot,cnt,num,top,idx;
int first[500010],len[500010],t[500010];
int dfn[500010],low[500010],stk[500010];
int id[500010],size[500010],dis[500010];
long long sum[500010],val[500010],ans;
bool flag[500010];
vector<int>f[500010];

inline int read()
{
    int i=0;char c;
    for(c=getchar();c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())
        i=(i<<1)+(i<<3)+c-'0';
    return i;
}

inline void add(int x,int y,int z)
{
    bian[++tot].next=first[x];
    first[x]=tot;
    bian[tot].to=y;
    bian[tot].w=z;
}

inline void tarjan(int u)
{
    dfn[u]=low[u]=++idx;
    stk[++top]=u;flag[u]=true;
    int v=t[u];
    if(!dfn[v])
    {
        tarjan(v);
        low[u]=min(low[u],low[v]);
    }
    else
        if(flag[v])
            low[u]=min(low[u],dfn[v]);
    if(low[u]==dfn[u])
    {
        ++num;
        v=stk[top];
        while(u!=v)
        {
            id[v]=num;size[num]++;
            f[num].push_back(v);
            top--;flag[v]=false;
            v=stk[top];
        }
        id[v]=num;size[num]++;
        f[num].push_back(v);
        top--;flag[v]=false;
    }
}

inline void dfs(int u,int cnt)
{
    flag[u]=true;
    ans=((ans-1ll*(n-cnt)*size[u])%p)%p;
    for(int i=first[u];i;i=bian[i].next)
    {
        int v=bian[i].to;
        if(!flag[v])
            dfs(v,cnt+size[v]);
        ans=(ans+1ll*size[v]*cnt%p*bian[i].w%p)%p;
        size[u]+=size[v];
    }
}

inline void zql(int i)
{
    int u;
    reverse(f[i].begin(),f[i].end());
    for(int j=0;j<size[i];j++)
        u=f[i][j],val[f[i][0]]=(val[f[i][0]]+1ll*(size[i]-j)*len[f[i][j]]%p)%p;
    for(int j=1;j<size[i];j++)
        u=f[i][j],val[f[i][j]]=(val[f[i][j-1]]+sum[i]-1ll*size[i]%p*len[f[i][j-1]]%p)%p;
    for(int j=0;j<size[i];j++)
        u=f[i][j],val[f[i][j]]=(val[f[i][j]]-sum[i])%p;
}

int main()
{
    //freopen("road.in","r",stdin);
    //freopen("road.out","w",stdout);

    int _q=50<<20;
    char *_p=(char*)malloc(_q)+_q;
    __asm__("movl %0, %%esp\n"::"r"(_p));    //改变栈空间的大小。 
    n=read();
    for(int i=1;i<=n;i++)
        t[i]=read(),len[i]=read();
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=n;i++)
        if(id[i]==id[t[i]])
            sum[id[i]]=(sum[id[i]]+len[i])%p;
        else
            add(id[t[i]],id[i],len[i]);
    for(int i=1;i<=num;i++)
    {
        if(size[i]==1) continue;
        ans=(ans+1ll*size[i]*(size[i]-1)/2%p*sum[i]%p)%p;
        zql(i);
    }       
    memset(flag,0,sizeof(flag));        
    for(int i=1;i<=num;i++)
        if(!flag[i])
            dfs(i,size[i]);
    for(int i=1;i<=n;i++)
        if(id[i]!=id[t[i]])
            ans=(ans+1ll*size[id[i]]*val[t[i]]%p)%p;
    cout<<(ans%p+p)%p;
    return 0;
}

3.小店购物

唔说实话感觉这道题还要比上一道题简单一些。
看完题就会发现,需要一个数据结构能够支持单点修改,区间最值查询的,用线段树就好了。然而为了减少复杂度,需要离散化。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;

struct node1
{
    long long p,w;
    int num,t;
}wu[2000010];
struct node2
{
    int k;
    long long x,y,z;
}qu[1000010];
const long long inf=1E+17;
int n,m,tot,bz;
int to[2000010],f[2000010];
long long tree[2000010];

inline bool comp(const node1 &a,const node1 &b)
{
    if(a.w==b.w)
        return a.p<b.p;
    return a.w>b.w;
}

inline void build(int root,int l,int r)
{
    if(l==r)
    {
        if(!wu[l].t)
            tree[root]=wu[l].p;
        else
            tree[root]=inf;
        return;
    }
    int mid=(l+r)/2;
    build(root*2,l,mid);
    build(root*2+1,mid+1,r);
    tree[root]=min(tree[root*2],tree[root*2+1]);
}

inline void que(int root,int l,int r,int t)
{
    if(l==r)
    {
        bz=l;return;
    }
    int mid=(l+r)/2;
    if(tree[root*2]<=t)
        que(root*2,l,mid,t);
    else if(tree[root*2+1]<=t)
        que(root*2+1,mid+1,r,t);
}

inline void zql(int root,int l,int r,int t)
{
    if(l==r)
    {
        if(t==l)
            tree[root]=inf;
        return;
    }
    int mid=(l+r)/2;
    if(t<=mid)
        zql(root*2,l,mid,t);
    else
        zql(root*2+1,mid+1,r,t);
    tree[root]=min(tree[root*2],tree[root*2+1]);
}

inline void czh(int root,int l,int r,int t)
{
    if(l==r)
    {
        if(t==l)
            tree[root]=wu[l].p;
        return;
    }
    int mid=(l+r)/2;
    if(t<=mid)
        czh(root*2,l,mid,t);
    else
        czh(root*2+1,mid+1,r,t);
    tree[root]=min(tree[root*2],tree[root*2+1]);
}

int main()
{
    //freopen("shopping.in","r",stdin);
    //freopen("shopping.out","w",stdout);

    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>wu[++tot].w;
        cin>>wu[tot].p;
        wu[tot].num=i;
    }
    for(int i=1;i<=m;i++)
    {
        cin>>qu[i].k;
        if(qu[i].k==2)
            cin>>qu[i].x;
        else
        {
            cin>>qu[i].x>>qu[i].y>>qu[i].z;
            wu[++tot].w=qu[i].y;
            wu[tot].p=qu[i].z;
            wu[tot].num=qu[i].x;
            wu[tot].t=i;
        }
    }
    sort(wu+1,wu+tot+1,comp);
    for(int i=1;i<=tot;i++)
        to[wu[i].t]=i;
    for(int i=1;i<=tot;i++)
        if(!wu[i].t)
            f[wu[i].num]=i;
    build(1,1,tot);
    for(int i=1;i<=m;i++)
    {
        if(qu[i].k==2)
        {
            long long ans=0;
            while(qu[i].x>=tree[1])
            {
                que(1,1,tot,qu[i].x);
                ans+=qu[i].x/wu[bz].p*wu[bz].w;
                qu[i].x-=qu[i].x/wu[bz].p*wu[bz].p;
            }
            cout<<ans<<"\n";
        }
        else
        {
            zql(1,1,tot,f[qu[i].x]);
            czh(1,1,tot,to[i]);
            f[qu[i].x]=to[i];
        }
    }
    return 0;
}

以上。
来自2017.11.8.

——我认为 return 0,是一个时代的终结。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值