2 条题解

  • 0
    @ 2025-10-8 17:04:18
    #include<bits/stdc++.h>
    using namespace std;  
    typedef long long LL;  
    const int N=2000005;
    LL sum[N],p[N],d[N],q[N],ok[N],n;
    template<typename T> void read(T& x)
    {
        x=0;char c=getchar();int f=1;
        for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
        for(; isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
        x=x*f;
    }
    void DP1()
    {
    	
    	int l=1,r=0;
    	for (int i=1; i<=n; ++i){
    		while (l<=r && sum[q[r]]>=sum[i]) --r;
    		q[++r]=i;
    	}
    	/*
    	思路:当前枚举到i,点(i-n)和i是同个点,那么研究 (i-n)->i能否顺利一圈。
    	判断方法:只要 sum[i-n+1]~sum[i]的 任意一个都大于等于sum[i-n]即可
    	 sum[i-n+1]~sum[i]中的最小值是sum[q[l]],所以只要判断 sum[q[l]]>=sum[i-n]即可证明。 
    	*/ 
    	for (int i=n+1; i<=n*2; ++i){
    		while (l<=r && sum[q[r]]>=sum[i]) --r;
    		q[++r]=i;
    		while (l<=r && q[l]<=i-n) ++l;
    		if(sum[q[l]]-sum[i-n]>=0) ok[i-n]=1;	
    	}
    }
    void DP2()
    {
    	int l=1,r=0;
    	for (int i=n*2; i>n; --i){
    		while(l<=r && sum[q[r]]>=sum[i]) --r;
    		q[++r]=i;
    	}
    	for (int i=n; i; --i){
    		while(l<=r && sum[q[r]]>=sum[i]) --r;
    		q[++r]=i;
    		while(l<=r && q[l]>=i+n) ++l;
    		if (sum[q[l]]-sum[i+n]>=0) ok[i]=1;		
    	}
    }
    int main()  
    {  
     	read(n);
     	sum[0]=p[0]=d[0]=0;
     	for (int i=1; i<=n; ++i)
    	 {
    		read(p[i]);p[i+n]=p[i];
    		read(d[i]);d[i+n]=d[i];
    		sum[i]=sum[i-1]+p[i-1]-d[i-1];
     	}
     	for (int i=n+1; i<=n*2; ++i)sum[i]=sum[i-1]+p[i-1]-d[i-1];
     	//sum[i]表示达到i点的汽油存量 
     	DP1();
     	
     	for (int i=n*2; i; --i) sum[i]=sum[i+1]+p[i+1]-d[i];
     	DP2();
     	
     	for (int i=1; i<=n; ++i) printf("%s\n",ok[i]?"TAK":"NIE");
     	return 0;
    }
    
    • 0
      @ 2025-10-8 17:04:02
      #include<bits/stdc++.h>
      using namespace std;  
      typedef long long LL;  
      const int N=2000005;
      LL sum[N],p[N],d[N],q[N],ok[N],n;
      template<typename T> void read(T& x)
      {
          x=0;char c=getchar();int f=1;
          for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
          for(; isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
          x=x*f;
      }
      void DP1()
      {
      	
      	int l=1,r=0;
      	for (int i=1; i<=n; ++i){
      		while (l<=r && sum[q[r]]>=sum[i]) --r;
      		q[++r]=i;
      	}
      	/*
      	思路:当前枚举到i,点(i-n)和i是同个点,那么研究 (i-n)->i能否顺利一圈。
      	判断方法:只要 sum[i-n+1]~sum[i]的 任意一个都大于等于sum[i-n]即可
      	 sum[i-n+1]~sum[i]中的最小值是sum[q[l]],所以只要判断 sum[q[l]]>=sum[i-n]即可证明。 
      	*/ 
      	for (int i=n+1; i<=n*2; ++i){
      		while (l<=r && sum[q[r]]>=sum[i]) --r;
      		q[++r]=i;
      		while (l<=r && q[l]<=i-n) ++l;
      		if(sum[q[l]]-sum[i-n]>=0) ok[i-n]=1;	
      	}
      }
      void DP2()
      {
      	int l=1,r=0;
      	for (int i=n*2; i>n; --i){
      		while(l<=r && sum[q[r]]>=sum[i]) --r;
      		q[++r]=i;
      	}
      	for (int i=n; i; --i){
      		while(l<=r && sum[q[r]]>=sum[i]) --r;
      		q[++r]=i;
      		while(l<=r && q[l]>=i+n) ++l;
      		if (sum[q[l]]-sum[i+n]>=0) ok[i]=1;		
      	}
      }
      int main()  
      {  
       	read(n);
       	sum[0]=p[0]=d[0]=0;
       	for (int i=1; i<=n; ++i)
      	 {
      		read(p[i]);p[i+n]=p[i];
      		read(d[i]);d[i+n]=d[i];
      		sum[i]=sum[i-1]+p[i-1]-d[i-1];
       	}
       	for (int i=n+1; i<=n*2; ++i)sum[i]=sum[i-1]+p[i-1]-d[i-1];
       	//sum[i]表示达到i点的汽油存量 
       	DP1();
       	
       	for (int i=n*2; i; --i) sum[i]=sum[i+1]+p[i+1]-d[i];
       	DP2();
       	
       	for (int i=1; i<=n; ++i) printf("%s\n",ok[i]?"TAK":"NIE");
       	return 0;
      }  
      
      • 1

      *【单调队列】[POI 2005]LOT-A Journey to Mars

      信息

      ID
      3188
      时间
      1000ms
      内存
      128MiB
      难度
      7
      标签
      递交数
      30
      已通过
      9
      上传者