The Preliminary Contest for ICPC Asia Nanjing 2019

The Preliminary Contest for ICPC Asia Nanjing 2019

A. The beautiful values of the palace(树状数组+二维前缀和)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (fabs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;

int t,n,m,q;
int ans[maxn];
ll C[maxn*10];

struct Node
{
    int x,y,id,val,f;
    bool operator<(const Node & b) const
    {
        if(x!=b.x)
            return x<b.x;
        if(y!=b.y)
            return y<b.y;
        return id<b.id;
    }
}p[maxn*5];

int lowbit(int x)
{
    return x&(-x);
}

void add(int pos,int val)
{
    for(int i=pos;i<=n;i+=lowbit(i))
        C[i]+=val;
}

ll getsum(int pos)
{
    int ret=0;
    for(int i=pos;i>0;i-=lowbit(i))
        ret+=C[i];
    return ret;
}

int getval(int x,int y)
{
    int t=min(min(x,y),min(n-x+1,n-y+1));
    int len=n-t*2+2;
    ll val=1ll*n*n-1ll*len*len;
    if(x==t)
        val+=2*len-1+y-t;
    else if(x==n-t+1)
        val+=n-y+1-(t-1);
    else if(y==t)
        val+=len+n-x+1-t;
    else if(y==n-t+1)
        val+=3*len-2+x-t;
    int ans=0;
    while(val)
    {
        ans+=val%10;
        val/=10;
    }
    return ans;
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=q;++i)
            ans[i]=0;
        for(int i=1;i<=n;++i)
            C[i]=0;

        for(int i=1;i<=m;++i)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int val=getval(x,y);
            p[i]={x,y,i,val,0};
        }
        int cnt=m;
        for(int i=m+1;i<=m+q;++i)
        {
            int x1,x2,y1,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            p[++cnt]={x1-1,y1-1,i,0,1};
            p[++cnt]={x1-1,y2,i,0,-1};
            p[++cnt]={x2,y1-1,i,0,-1};
            p[++cnt]={x2,y2,i,0,1};
        }

        sort(p+1,p+1+cnt);
        for(int i=1;i<=cnt;++i)
        {
            if(p[i].id<=m)
                add(p[i].y,p[i].val);
            else
                ans[p[i].id-m]+=getsum(p[i].y)*p[i].f;
        }
        for(int i=1;i<=q;++i)
            printf("%d\n",ans[i]);
    }
	return 0;
}

B. super_log(欧拉降幂)

题意:求解 a a … a a^{a^{\dots^a}} aaa % m的值
思路:m等于1的时候,返回 x % m + m x\%m+m x%m+m,即返回1。递归出口返回1还是0,取决于后面的操作,如果后面还有判断的操作,就返回x%m,否则就返回x%m+m

#include <iostream>
#include <algorithm>
#include <cstdio>
#define ll long long
using namespace std;

int t;
ll a,b,m;

ll mm(ll x,ll m)
{
    return x<m?x:x%m+m;
}

ll qpow(ll base,ll n,ll mod)
{
    ll ret=1;
    while(n)
    {
        if(n&1)
            ret=mm(ret*base,mod);
        base=mm(base*base,mod);
        n>>=1;
    }
    return ret;
}

ll phi(ll n)
{
    ll a=n,ans=n;
    for(ll i=2;i*i<=a;++i)
    {
        if(a%i==0)
        {
            ans=ans/i*(i-1);
            while(a%i==0)
                a/=i;
        }
    }
    if(a>1)
        ans=ans/a*(a-1);
    return ans;
}

ll solve(ll a,ll b,ll m)
{
    if(m==1)
        return 1;
    if(b==0)
        return 1;
    ll x=solve(a,b-1,phi(m));
    return qpow(a,x,m);
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld%lld",&a,&b,&m);
        printf("%lld\n",solve(a,b,m)%m);
    }   
	return 0;
}

C. Tsy’s number 5(NTT)

题意:给出n,求 ∑ i = 1 n ∑ j = 1 n φ ( i ) φ ( j ) 2 φ ( i ) φ ( j ) \sum_{i=1}^n\sum_{j=1}^n \varphi(i)\varphi(j)2^{\varphi(i)\varphi(j)} i=1nj=1nφ(i)φ(j)2φ(i)φ(j)模998244353的值
思路:设 f ( i ) = ∑ k = 1 n [ φ ( k ) = i ] f(i)=\sum_{k=1}^n[\varphi(k)=i] f(i)=k=1n[φ(k)=i]
原式化简为:
核心思想就是:把多个 i i i 相等的 φ ( i ) \varphi(i) φ(i),合并在一起统计,枚举到i这个数的时候,就把它当做欧拉函数的值。 f ( i ) f(i) f(i)就是这个函数值在 [ 1 , n ] [1,n] [1,n]出现的次数
∑ i = 1 n ∑ j = 1 n f ( i ) f ( j ) i j 2 i j \sum_{i=1}^n\sum_{j=1}^n f(i)f(j)ij2^{ij} i=1nj=1nf(i)f(j)ij2ij

又有 2 i j = 2 ( i + j ) 2 − i 2 − j 2 2 = 2 ( i + j ) 2 − i 2 − j 2 2^{ij}=2^{\frac {(i+j)^2-i^2-j^2}2}=\sqrt2 ^{(i+j)^2-i^2-j^2} 2ij=22(i+j)2i2j2=2 (i+j)2i2j2

因此所求就是

∑ i = 1 n f ( i ) i 2 − i 2 ∑ j = 1 n f ( j ) j 2 − j 2 2 ( i + j ) 2 \sum_{i=1}^nf(i)i\sqrt2 ^{-i^2}\sum_{j=1}^nf(j)j\sqrt2^{-j^2}\sqrt2^{(i+j)^2} i=1nf(i)i2 i2j=1nf(j)j2 j22 (i+j)2

然后NTT右边的式子,就可以了

贴一份题解的推导
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (fabs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=998244353,sqrt2=116195171;

ll qpow(ll base,ll n,ll mod)
{
    ll ret=1;
    while(n)
    {
        if(n&1)
            ret=ret*base%mod;
        n>>=1;
        base=base*base%mod;
    }
    return ret;
}

const int G=3,P=998244353,GI=332748118;
struct NTT
{
	int total,digit,rev[maxn*6];
	ll a[maxn*6],b[maxn*6];
	
	void init(int len)
	{
		total=1,digit=0;
		while(total<=len)
			total<<=1,digit++;
		for(int i=0;i<total;++i)
		{
			rev[i]=(rev[i>>1]>>1)|(i&1)<<(digit-1);
			a[i]=0,b[i]=0;
		}	
	}
	
	void ntt(ll *A,int f)
	{
		for(int i=0;i<total;++i)
			if(i<rev[i])
				swap(A[i],A[rev[i]]);
			
		for(int mid=1;mid<total;mid<<=1)
		{
			ll Wn,len=mid*2;;
			if(f==1)
				Wn=qpow(G,(P-1)/len,P);
			else
				Wn=qpow(GI,(P-1)/len,P);
			for(int p=0;p<total;p+=len)
			{
				ll Wk=1;
				for(int k=0;k<mid;++k)
				{
					int x=A[p+k],y=Wk*A[p+k+mid]%P;
					A[p+k]=(x+y)%P;
					A[p+k+mid]=(x-y+P)%P; 	
					Wk=Wk*Wn%P;	
				}		
			}	
		}	
		
		if(f==-1)
		{
			ll inv=qpow(total,P-2,P);
			for(int i=0;i<total;++i)
				a[i]=a[i]*inv%P; 
		}
	}
	
	void calc()
	{
		ntt(a,1),ntt(b,1);
		for(int i=0;i<total;++i)
			a[i]=a[i]*b[i]%P;
		ntt(a,-1);
	}
}ntt;

const int N=1e5+10;
int visit[N+10],prime[N+10],cnt;
int phi[N+10];

void init()
{
    cnt=0,phi[1]=1;
    for(int i=2;i<=N;++i)
    {
        if(!visit[i])
            prime[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
        {
            visit[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    }
}

int n,t;
ll f[maxn],a[maxn];

int main()
{
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        ntt.init(3*n);
        for(int i=0;i<=n;++i)
            f[i]=0;
        for(int i=1;i<=n;++i)
            f[phi[i]]++;
        for(int i=1;i<=n;++i)
            a[i]=ntt.a[i]=1ll*f[i]*i%mod*qpow(sqrt2,-1ll*i*i%(mod-1)+mod-1,mod)%mod;
        for(int i=1;i<=2*n;++i)
            ntt.b[i]=qpow(sqrt2,1ll*i*i%(mod-1),mod);
        reverse(ntt.a+1,ntt.a+1+n);
        ntt.calc();
        ll ans=0;
        for(int i=1;i<=n;++i)
            ans=(ans+1ll*a[i]*ntt.a[n+i+1])%mod;
        printf("%lld\n",ans);
    }  
	return 0;
}

D. Robots

E. K Sum(推式子+积性函数线性筛+等比数列求和+欧拉降幂)

题意:定义 f n ( k ) = ∑ l 1 n ∑ l 2 n ⋯ ∑ l k n g c d ( l 1 , l 2 , … , l k ) 2 f_n(k)=\sum_{l_1}^n\sum_{l_2}^n\dots\sum_{l_k}^n gcd(l_1,l_2,\dots,l_k)^2 fn(k)=l1nl2nlkngcd(l1,l2,,lk)2,给定n,k,求 ∑ i = 2 k f n ( i ) \sum_{i=2}^k f_n(i) i=2kfn(i),对1e9+7取模

思路:推式子+杜教筛+等比数列求和
推导过程挺简单的,关键是后面的处理。
最终推得的式子为:
∑ T = 1 n ∑ d ∣ T μ ( d ) ( T d ) 2 ∑ i = 2 k ⌊ n T ⌋ i \sum_{T=1}^n\sum_{d|T}\mu(d)(\frac Td)^2 \sum_{i=2}^k\lfloor \frac nT\rfloor ^i T=1ndTμ(d)(dT)2i=2kTni

f ( T ) = ∑ d ∣ T μ ( d ) ( T d ) 2 f(T)=\sum_{d|T}\mu(d)(\frac Td)^2 f(T)=dTμ(d)(dT)2,因此就是求左边一个积性函数前缀和,右边一个等比数列前缀和
1、积性函数前缀和,用杜教筛,首先对积性函数做线性筛
f ( 1 ) = 1 f(1)=1 f(1)=1
f ( p ) = p 2 − 1 f(p)=p^2-1 f(p)=p21
f ( p k ) = p 2 k − p 2 k − 2 f(p^k)=p^{2k}-p^{2k-2} f(pk)=p2kp2k2
f ( p k + 1 ) = p 2 k + 2 − p 2 k f(p^{k+1})=p^{2k+2}-p^{2k} f(pk+1)=p2k+2p2k
2、然后观察f(T)的卷积, f ( T ) = μ ∗ ( i d ) 2 f(T)=\mu*(id)^2 f(T)=μ(id)2
我们要凑一个h, h = f ∗ g = u ∗ ( i d ) 2 ∗ g h=f*g=u*(id)^2*g h=fg=u(id)2g,这时我们知道 μ ∗ I = ϵ \mu*I=\epsilon μI=ϵ,因此我们卷上 I I I,即 h = i d 2 h=id^2 h=id2
这样就可以将g、h带入公式了
S ( n ) = ∑ i = 1 n i 2 − ∑ d = 2 n S ( ⌊ n d ⌋ ) S(n)=\sum_{i=1}^ni^2-\sum_{d=2}^nS(\lfloor \frac nd\rfloor) S(n)=i=1ni2d=2nS(dn)

3、我们再处理右边的等比数列,设 q = ⌊ n T ⌋ q=\lfloor \frac nT \rfloor q=Tn

  1. 当q=1时,即k-1,k很大直接对mod取模
  2. 当q不为1时,即 q 2 + q 3 + ⋯ + q k q^2+q^3+\dots+q^k q2+q3++qk,求和后化简,即:
    q k + 1 − q 2 q 2 − 1 \frac {q^{k+1}-q^2}{q^2-1} q21qk+1q2

k很大,又在指数的位置,所以这个k需要对 m o d − 1 mod-1 mod1取模

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (fabs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;

int inv6;

int qpow(int base,int n,int mod)
{
    int ret=1;
    while(n)
    {
        if(n&1)
            ret=1ll*ret*base%mod;
        base=1ll*base*base%mod;
        n>>=1;
    }
    return ret;
}

const int N=1e6;
int prime[N+10],visit[N+10],cnt;
ll f[N+10],low[N+10];

void init()
{
    cnt=0,f[1]=1;
    for(int i=2;i<=N;++i)
    {
        if(!visit[i])
            prime[++cnt]=i,f[i]=(1ll*i*i-1)%mod,low[i]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
        {
            visit[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                low[i*prime[j]]=low[i]*prime[j];
                if(low[i]==i)
                    f[i*prime[j]]=f[i]*prime[j]%mod*prime[j]%mod;
                else
                    f[i*prime[j]]=f[i/low[i]]*f[low[i]*prime[j]];
                break;
            }
            low[i*prime[j]]=prime[j];
            f[i*prime[j]]=f[i]*f[prime[j]];
        }
    }
    for(int i=1;i<=N;++i)
        f[i]=(f[i]+f[i-1])%mod;
}

int abss(int x)
{
    if(x<0)
        x+=mod;
    return x;
}

unordered_map<int,int> mf;

int S(int n)
{
    if(n<=N)
        return f[n];
    if(mf[n])
        return mf[n];
    int ans=1ll*n*(n+1)%mod*(2*n+1)%mod*inv6%mod,l=2,r;
    while(l<=n)
    {
        r=n/(n/l);
        ans=(ans-1ll*(r-l+1)*S(n/l)%mod+mod)%mod;
        l=r+1;
    }
    return mf[n]=ans;
}

int G(int q,int k1,int k2)
{
    if(q==1)
        return (k1-1+mod)%mod;
    int ans=abss(1ll*qpow(q,k2+1,mod)-1ll*q*q%mod);
    return 1ll*ans*qpow(q-1,mod-2,mod)%mod;
}

int t,n;
string k;

int main()
{
    inv6=qpow(6,mod-2,mod);
    init();
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        int k1=0,k2=0;
        for(auto i : k)
        {
            k1=(1ll*k1*10+i-'0')%mod;
            k2=(1ll*k2*10+i-'0')%(mod-1);
        }

        int l=1,r,ans=0;
        while(l<=n)
        {
            r=n/(n/l);
            ans=(1ll*ans+1ll*abss(S(r)-S(l-1))*G(n/l,k1,k2)%mod)%mod;
            l=r+1;
        }
        printf("%d\n",ans);
    }
	return 0;
}

F. Greedy Sequence(主席树||线段树||滑动窗口)

解法一:主席树

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define isZero(d)  (fabs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;

int t,n,k;
int a[maxn],pos[maxn],ans[maxn];
int root[maxn],ST[maxn*40],ls[maxn*40],rs[maxn*40],no;

int Build(int L,int R)
{
    int rt=++no;
    ST[rt]=0;
    if(L==R)
        return rt;
    int mid=(L+R)>>1;
    ls[rt]=Build(L,mid);
    rs[rt]=Build(mid+1,R);
    return rt;
}

int Update(int pre,int p,int L,int R)
{
    int rt=++no;
    ls[rt]=ls[pre];
    rs[rt]=rs[pre];
    ST[rt]=ST[pre]+1;
    if(L==R)
        return rt;
    int mid=(L+R)>>1;
    if(p<=mid)
        ls[rt]=Update(ls[pre],p,L,mid);
    if(p>mid)
        rs[rt]=Update(rs[pre],p,mid+1,R);
    return rt;
}

int Query(int pre,int now,int p,int L,int R)
{
    if(ST[now]-ST[pre]==0)
        return -1;
    if(L==R)
        return L<p?L:-1;
    int mid=(L+R)>>1;
    int x=-1;
    if(p>mid+1)
        x=Query(rs[pre],rs[now],p,mid+1,R);
    if(x!=-1)
        return x;
    return Query(ls[pre],ls[now],p,L,mid);
}


int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
            pos[a[i]]=i;
            ans[i]=0;
        }
        no=0;
        root[0]=Build(1,n);
        for(int i=1;i<=n;++i)
            root[i]=Update(root[i-1],a[i],1,n);
        
        for(int i=1;i<=n;++i)
        {
            int l=max(pos[i]-k,1);
            int r=min(pos[i]+k,n);
            int x=Query(root[l-1],root[r],i,1,n);
            ans[i]=ans[x]+1;
        }
        for(int i=1;i<=n;++i)
            printf("%d%c",ans[i],i==n?'\n':' ');
    }
	return 0;
}

解法二:线段树

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (fabs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;

int t,n,k;
int a[maxn],pos[maxn],ST[maxn<<2];
int ans[maxn];

void Push_up(int rt)
{
    ST[rt]=max(ST[ls],ST[rs]);
}


void Build(int rt,int L,int R)
{
    ST[rt]=0;
    if(L==R)
        return;
    int mid=(L+R)>>1;
    Build(ls,L,mid);
    Build(rs,mid+1,R);
}

void Update(int rt,int p,int L,int R,int val)
{
    if(L==R)
    {
        ST[rt]=val;
        return;
    }
    int mid=(L+R)>>1;
    if(p<=mid)
        Update(ls,p,L,mid,val);
    if(p>mid)
        Update(rs,p,mid+1,R,val);
    Push_up(rt);
}

int Query(int rt,int l,int r,int L,int R)
{
    if(l<=L&&R<=r)
        return ST[rt];
    int maxx=0;
    int mid=(L+R)>>1;
    if(l<=mid)
        maxx=max(maxx,Query(ls,l,r,L,mid));
    if(r>mid)
        maxx=max(maxx,Query(rs,l,r,mid+1,R));
    return maxx;
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]),pos[a[i]]=i;
        Build(1,1,n);
        
        for(int i=1;i<=n;++i)
        {
            int l=max(pos[i]-k,1);
            int r=min(pos[i]+k,n);
            int x=Query(1,l,r,1,n);
            ans[i]=ans[x]+1;
            Update(1,pos[i],1,n,i);
        }

        for(int i=1;i<=n;++i)
            printf("%d%c",ans[i],i==n?'\n':' ');
    }
	return 0;
}

解法三:滑动窗口

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (abs(d) < 1e-8)
using namespace std;
const int maxn=1e5+5,INF=0x3f3f3f3f;
const int mod=1e9+7;

int t,n,k,a[maxn],pos[maxn],l[maxn],r[maxn];
int ans[maxn];

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d %d",&n,&k);
		rep(i,1,n)	
		{
			scanf("%d",&a[i]);
			l[i]=r[i]=0;
			pos[a[i]]=i;
		}
		
		set<int> s;	
		for(int i=1;i<=n;++i)
		{
			s.insert(a[i]);
			if(i-k-1>=1)
				s.erase(a[i-k-1]);
			auto it=s.lower_bound(a[i]);
			if(it!=s.begin())
				l[a[i]]=*(--it);					
		}
		s.clear();
		for(int i=n;i>=1;--i)
		{
			s.insert(a[i]);
			if(i+k+1<=n)
				s.erase(a[i+k+1]);
			auto it=s.lower_bound(a[i]);
			if(it!=s.begin())
				r[a[i]]=*(--it);
		}
		
		for(int i=1;i<=n;++i)
		{		
			int x=max(l[i],r[i]);
			ans[i]=ans[x]+1;	
			printf("%d%c",ans[i],i==n?'\n':' ');	
		}
	} 
	return 0;
}

G. Quadrilateral(容斥)

#include <iostream>
#include <algorithm>
#include <cstdio>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define ll long long
using namespace std;

int T,x[10];

ll f(ll n)
{
	return (1+n)*n/2;
}

ll f2(ll n)
{
	return n*(n+1)*(n+2)/6;
}

ll cal(ll a,ll b,ll c)
{
	if(a<1||b<1||c<2)
		return 0;		
	a=min(a,c-1);
	b=min(b,c-1);
	if(a+b<=c)
		return (f(c-1)-f(c-b-1)+f(c-a)-f(c-a-b))*a/2;
	else
		return (f(c-1)-f(c-b-1)+f(b))*(c-b)/2+f2(b-1)-f2(c-a-1);
}

ll solve(ll a,ll b,ll c,ll d)
{
	if(a<1||b<1||c<1||d<1)
		return 0;
	ll ret=1ll*a*b*c;
	ret-=cal(b,c,d-1)-cal(b,c,d-a-1);
	ret-=cal(a,b,c-d);
	ret-=cal(a,c,b-d);
	ret-=cal(b,c,a-d);
	return ret;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
    	rep(i,1,8)
    		scanf("%d",&x[i]);
    	ll ans=0;
    	for(int i=x[7];i<=x[8];++i)
    	{
    		ans+=solve(x[2],x[4],x[6],i)-solve(x[1]-1,x[4],x[6],i)-solve(x[2],x[3]-1,x[6],i)
    		-solve(x[2],x[4],x[5]-1,i)+solve(x[1]-1,x[3]-1,x[6],i)+solve(x[1]-1,x[4],x[5]-1,i)
    		+solve(x[2],x[3]-1,x[5]-1,i)-solve(x[1]-1,x[3]-1,x[5]-1,i);
    	}
    	printf("%lld\n",ans);
    }
	return 0;
}

H. Holy Grail

I. Washing clothes

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值