• 2018-2019 Summer Petrozavodsk Camp, Oleksandr Kulkov Contest 2解题报告


    C


    签到题,计算前缀和,把所有的负项加入到一个set中,如果当前前缀和小于0,则从set中从小到大弹出负项,并且把弹出的项加回到前缀和中。


    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    #define PII pair<ll,int>
    #define fr first
    #define sc second
    #define mp make_pair
    
    const int N=2e5+7;
    
    set<PII> s;
    ll a[N],sum;
    char Ans[N][20];
    
    int main(){
    	int n=input()+input();
    	for(int i=1;i<=n;i++){
    		a[i]=input();
    		sum+=a[i];
    		if(a[i]>0) strcpy(Ans[i],"resupplied");
    		else{
    			strcpy(Ans[i],"approved");
    			s.insert(mp(-a[i],i));
    		}
    		while(sum<0){
    			auto it=--s.end();
    			sum+=it->fr;
    			strcpy(Ans[it->sc],"declined");
    			s.erase(it);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		printf("%s
    ",Ans[i]);
    	}
    }
    

    E


    本题需要用到五边形数定理:

    [prod_{n=1}^infty(1-x^n)=sum_{k=-infty}^infty(-1)^kx^{frac{k(3k-1)}{2}}=sum_{k=0}^infty(-1)^kx^{frac{k(3kpm1)}{2}}\ (1-x)(1-x^2)(1-x^3)cdots=1-x-x^2+x^5+x^7-x^{12}-x^{15}+x^{22}+x^{26}cdots ]

    观察系数关系知符号关系为(+--++--++--)除去前三项可以分类讨论。例如某一段是( +x^a+x^b-x^c-x^d),那么(a)的位置是(1),([a+1,b])位置是(0)([b+1,c-1])位置是(9)(c)位置是(8)([c+1,d])位置是(9)。然后通过二分判断某一位在那个位置就好了。


    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    ll f(ll k){return k*(k*3+1)/2;}
    
    int main(){
    	int T=input();
    	while(T--){
    		ll n=input();
    
    		ll l=0,r=1e9,k;
    		while(l<=r){
    			ll mid=(l+r)>>1;
    			if(f(mid)<n) k=mid,l=mid+1;
    			else r=mid-1;
    		}
    		
    		ll nr=f(k++);
    
    		int Ans=0;
    		if(k&1){
    			if(n==nr+2*k-1) Ans=8;
    			else if(n<=nr+3*k-1) Ans=9;
    			else Ans=0;
    		}else{
    			if(n==nr+2*k-1) Ans=1;
    			else if(n<=nr+3*k-1) Ans=0;
    			else Ans=9;
    		}
    		printf("%d%c",Ans,T==0?'
    ':' ');
    	}
    }
    

    B


    神仙题QWQ。

    首先我们进行一个简单的转化:

    [C_k=max_{gcd(i,j)=k}^n|A_i-B_i| \ C_k=max_{gcd(i,j)=k}^nmax(A_i-B_i,B_i-A_i) \ ]

    不妨令(B_i=-B_i),方便我们进行推导,式子就变为了:

    [C_k=max_{gcd(i,j)=k}^n(A_i+B_j) ]

    然后反演的标准套路:

    [C_k=max_{k|i}^n(A_i+max_{gcd(i,j)=k}^nB_j)\ C_k=max_{k|i}^n(A_i+max_{k|j}^n B_j[gcd(i,j)==k])\ C_k=max_{i=1}^{frac{n}{k}}(A_{ik}+max_{j=1}^{frac{n}{k}} B_{jk}[gcd(i,j)==1])\ ]

    现在问题转换为了了解决若干个(C=max_{i=1}^{m}(A_{i}+max_{j=1}^{m} B_{j}[gcd(i,j)==1]))这样的子问题。

    然而(max)函数很难在这样的多项式中进行计算,我们需要考虑转化。

    我们发现二分对这个(max)函数非常友好,我们不妨考虑一个这样的函数

    [check(mid)=sum_{j=1}^m[mid le B_j] sum_{d|i & d|j}mu(d) ]

    然后又是一个反演的标准套路

    [check(mid)=sum_{d|i}mu(d)sum_{d|j}[mid le B_j] ]

    对应(check(mid))的解释:假设当前二分到的答案是mid,如果(check(mid)>0)那么存在一个值比mid大,反之则不存在。满足二分的条件。

    现在问题变成了对于每个(i)通过二分询问合法的(B_j),刚好可以通过整体二分来实现询问。

    复杂度不会证。大概是(O(nlog^3n))吧。


    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    const int N=1e5+7;
    
    #define pb push_back
    
    int mu[N],pri[N],cnt=0,vis[N];
    vector<int> d[N];
    
    void init(){
        mu[1]=1;
        for(int i=2;i<=N;++i){
            if(!vis[i]) pri[++cnt]=i,mu[i]=-1;
            for(int j=1;j<=cnt;++j){
                if(i*pri[j]>N) break;
                vis[i*pri[j]]=1;
                if(i%pri[j]==0){mu[i*pri[j]]=0;break;}
                else mu[i*pri[j]]=-mu[i];
            }
        }
        for(int i=1;i<=N;i++)
       		for(int j=i;j<=N;j+=i) d[j].pb(i);
    }
    
    int A[N],B[N],n,Ans[N];
    int q[N],ql[N],qr[N],sum[N],now,res[N];
    int ta[N],tb[N],tmp[N],rev[N];
    
    void _solve(int l,int r,int head,int tail){
    	if(head>tail) return;
    	if(l==r){
    		for(int i=head;i<=tail;i++) res[q[i]]=l;
    		return;
    	}
    
    	int mid=(l+r)>>1;
    	int lcnt=0,rcnt=0;
    
    	while(now<mid){
    		int x=rev[++now];
    		for(int i:d[x]) --sum[i];
    	}
    	while(now>mid){
    		int x=rev[now--];
    		for(int i:d[x]) ++sum[i];
    	}
    
    	for(int i=head;i<=tail;i++){
    		int tt=0;
    		for(int j:d[q[i]]) tt+=sum[j]*mu[j];
    		if(tt<=0) ql[++lcnt]=q[i];
    		else qr[++rcnt]=q[i];
    	}
    
    	tail=head-1;
    	for(int i=1;i<=lcnt;i++) q[++tail]=ql[i];
    	int div=tail;
    	for(int i=1;i<=rcnt;i++) q[++tail]=qr[i];
    	_solve(l,mid,head,div),_solve(mid+1,r,div+1,tail);
    }
    
    int work(int tn){
    	for(int i=1;i<=tn;i++) tmp[q[i]=i]=tb[i],sum[i]=0;now=tn;
    
    	sort(tmp+1,tmp+1+tn);
    	
    	for(int i=1;i<=tn;i++){
    		int x=upper_bound(tmp+1,tmp+1+tn,tb[i])-tmp-1;
    		rev[x]=i;tmp[x]++;
    	}
    
    	int ret=-1e9;_solve(1,tn,1,tn);
    	for(int i=1;i<=tn;i++)
    		ret=max(ret,tmp[res[i]]+ta[i]-1);
    	return ret;
    }
    
    void solve(){
    	for(int i=1;i<=n;i++){
    		for(int j=1;j*i<=n;j++)
    			ta[j]=A[i*j],tb[j]=B[i*j];
    		Ans[i]=max(Ans[i],work(n/i));
    	}
    }
    
    int main(){
    	init();
    	n=input();
    	for(int i=1;i<=n;i++) A[i]=input();
    	for(int i=1;i<=n;i++) B[i]=-input();
    	solve();
    	for(int i=1;i<=n;i++) A[i]=-A[i],B[i]=-B[i];
    	solve();
    	
    	for(int i=1;i<=n;i++) printf("%d%c",Ans[i],i==n?'
    ':' ');
    }
    
  • 相关阅读:
    ASP.Net Cms
    GetHashCode函数所存在的陷阱
    NH的系统架构
    Icomparable<T> 和 Icomparaer<T> 实现顺序关系
    《创业法典》:用流程图告诉你如何创业
    创业之前,网站先行
    杨卫华:新浪微博的架构发展历程
    技术开发人员为什么会无奈苦逼?
    使用面向对象的、完整的单点登录功能
    SilverLight之我见
  • 原文地址:https://www.cnblogs.com/-aether/p/12606995.html
Copyright © 2020-2023  润新知