wannafly练习赛8

来源:互联网 发布:audition cc 2018 mac 编辑:程序博客网 时间:2024/05/29 08:01

https://www.nowcoder.com/acm/contest/39#question
收获:学习了容斥原理(一语成谶,当亚洲赛开始前我告诉自己,如果现在不努力学习算法,以后肯定还要在学习,但是那个时候学习的时候就有一点悲伤的感觉了qwq),和a,b的脑洞。a是数学脑洞,b是前缀和,也有线段树。(然而不加挂都过不去)
不足:线段树代码明显写的不好,码力还是不行。慢慢提高吧qwq
A :给定n,求1-n中每个数的 约数和的和。
思路:开始蒙蔽,后来发现枚举约数1-n,除一下就行了(商就是n内有多少个)

#include <bits/stdc++.h>using namespace std;/**/int main(){   int m;    scanf("%d",&m);    int sum=0;    for(int i=1;i<=m;i++){        sum+=m/i;    }    printf("%d\n",sum);    return 0;}

B 一个数轴,每一个储物点会有一些东西,同时它们之间存在距离。
每次给个区间[l,r],查询把这个区间内所有储物点的东西运到另外一个储物点的代价是多少?
比如储物点i有x个东西,要运到储物点j,代价为x * dist( i , j )
dist就是储物点间的距离。
思路:用前缀和维护一下,维护距离,数量和 距离*数量的前缀和。
分两种情况。当要移动的位置x在区间左边。 和再区间右边。
(具体可以这样理解,物品从区间移动到最左边,然后再移动到x,当x区间左边时,)
线段树也是这样

#include<bits/stdc++.h>using namespace std;#define LL long long#define MN 200010int n,m,ll,rr,dis[MN],sum1[MN],sum2[MN],a[MN],x,p=1e9+7;int work(int l,int r,int k,int x){    if(l>r) return 0;    return     k==-1?((sum1[r]-sum1[l-1]+p)%p-((LL)dis[x]*((sum2[r]-sum2[l-1]+p)%p))%p+p)%p    :(((LL)dis[x]*((sum2[r]-sum2[l-1]+p)%p))%p-(sum1[r]-sum1[l-1]+p)%p+p)%p;}int main(){//  freopen("sample3.in","r",stdin);//  freopen("a.txt","w",stdout);    cin>>n>>m;for(int i=2,_;i<=n;i++)     cin>>_,dis[i]=(dis[i-1]+_)%p;//sum1[i]=(sum1[i-1]+dis[i])%p;    for(int i=1;i<=n;i++)     cin>>a[i],a[i]%=p,sum2[i]=(sum2[i-1]+a[i])%p,sum1[i]=(sum1[i-1]+((LL)a[i]*dis[i])%p)%p;//  for(int i=1;i<=n;i++) if(sum2[i]<0||dis[i]<0||a[i]<0) cout<<" swdwd";    while(m--)    {        cin>>x>>ll>>rr;        if(x>rr) cout<<work(ll,rr,1,x)<<endl;        else if(x<ll) cout<<work(ll,rr,-1,x)<<endl;        else cout<<(work(ll,x-1,1,x)+work(x+1,rr,-1,x))%p<<endl;    }     return 0;}
#include<cstdio>#include<cstring>#include<algorithm>#define LL long long intusing namespace std;const int maxn = 200005,P = 1e9+7;inline LL read(){    LL out = 0,flag = 1;char c = getchar();    while (c < 48 || c > 57) {if (c == '-') flag = -1;c = getchar();}    while (c >= 48 &&c <= 57) {out = out * 10 + c - 48;c = getchar();}    return out * flag;}LL n,m,Sum[maxn],A[maxn];void init(){    n = read();    m = read();    Sum[1] = 0;    for (int i = 2; i <= n; i++)        Sum[i] = (Sum[i - 1] + read()) % P;    for (int i = 1; i <= n; i++)        A[i] = read() % P;}LL V[2][4 * maxn],sum[4 * maxn];void build(int u,int l,int r){    if (l == r){        V[0][u] = V[1][u] = 0;        sum[u] = A[l];    }else {        int mid = (l + r) >> 1;        build(u << 1,l,mid);        build(u << 1 | 1,mid + 1,r);        V[0][u] = (V[0][u<<1] + V[0][u<<1|1] + sum[u<<1|1] * (Sum[mid + 1] - Sum[l]) % P) % P;        V[1][u] = (V[1][u<<1] + V[1][u<<1|1] + sum[u<<1] * (Sum[r] - Sum[mid]) % P) % P;        sum[u] = (sum[u << 1] + sum[u << 1 | 1]) % P;    }}struct node{    LL v,sum,l,r;};int L,R;node Query(int u,int l,int r,int p){    if (l >= L && r <= R){        return (node){V[p][u],sum[u],l,r};    }else {        int mid = (l + r) >> 1;        if (mid >= R) return Query(u<<1,l,mid,p);        else if (mid < L) return Query(u<<1|1,mid + 1,r,p);        else {            node a = Query(u<<1,l,mid,p),b = Query(u<<1|1,mid + 1,r,p);            if (p == 0){                return (node){(a.v + b.v + b.sum * (Sum[mid + 1] - Sum[a.l]) % P) % P,(a.sum + b.sum) % P,a.l,b.r};            }else {                return (node){(a.v + b.v + a.sum * (Sum[b.r] - Sum[mid]) % P) % P,(a.sum + b.sum) % P,a.l,b.r};            }        }    }}void solve(){    LL x,l,r,ans;    node u;    while (m--){        x = read();        l = read();        r = read();        if (x <= l){            L = l; R = r;            u = Query(1,1,n,0);            printf("%lld\n",((u.v + u.sum * (Sum[l] - Sum[x]) % P) % P + P) % P);        }else if (x >= r){            L = l; R = r;            u = Query(1,1,n,1);            printf("%lld\n",((u.v + u.sum * (Sum[x] - Sum[r]) % P) % P + P) % P);        }else {            L = x; R = r;            u = Query(1,1,n,0);            ans = u.v;            L = l; R = x;            u = Query(1,1,n,1);            ans =((ans + u.v) % P + P) % P;            printf("%lld\n",ans);        }    }}int main(){    init();    build(1,1,n);    solve();    return 0;}

D直接写就行,这个比较水qwq,求联通分量之后,-1就行。(特判为1)

include <bits/stdc++.h>using namespace std;/* 水题?分块?*/const int maxn=1e5+200;bool vis[maxn];int m,n;vector<int>g[maxn];void dfs(int u){     for(int i=0;i<g[u].size();i++){          int to=g[u][i];          if(!vis[to]){            vis[to]=true;            dfs(to);          }     }}int main(){   int a,b;    scanf("%d%d",&m,&n);    memset(vis,false,sizeof(vis));      for(int i=0;i<n;i++){          scanf("%d%d",&a,&b);          g[a].push_back(b);          g[b].push_back(a);      }      int sum=0;      for(int i=1;i<=m;i++){          if(!vis[i]){            vis[i]=true;            dfs(i);            sum++;          }      }      printf("%d\n",sum-1);    return 0;}

E :容斥。求出n的全排列,其实我感觉这个写法很模板qwq。

#include <bits/stdc++.h>using namespace std;/* 容斥原理。   现在学这种东西,心里是很伤心的,   伤心自己以前没有好好看数学的东西qwq   主要是比赛前太害怕搜索会出事了*/typedef long long ll;const int maxn=25;int va[maxn];int n;ll m;ll solve(int s,ll num){    ll sumall=0;    for(int i=0;i<(1<<s);i++){        int tim=0;        ll sum=1;        for(int j=0;j<s;j++){             if(i&(1<<j)){                sum*=va[j];                tim++;             }        }        if(tim%2){            sumall+=num/sum;        }        else if(tim!=0){            sumall-=num/sum;        }        //cout<<sumall<<" "<<num<<" "<<sum<<endl;    }    return sumall;}int main(){   int a;ll b;    while(~scanf("%d%lld",&a,&b)){           for(int i=0;i<a;i++){               scanf("%d",&va[i]);           }           printf("%d\n",solve(a,b));      }    return 0;}