简记2013 ACM/ICPC Asia Regional Changsha Online

    今晚刚搞完的长沙网络赛,在ZOJ上办的。我们三个水货出了3题,罚时挺多。

    比赛开始就在看J题,和JX简单讨论下,然后说我来敲。脑袋不是很清醒,想的也不周密,最后终于终于在两个半小时之后A了= =题目本身不难,但是容易犯错,想得不够周密呀。简单来说就是:如果n%3==2,那么我们能将第3个,第6个,……,第n-2个数字通过公式求出来。首先sum[1]-sum[0]得到第3个数字的值,然后递推就好了。这时我们假定第一个数a[0]=0,求出所有的数字的值,此时a[1],a[4],a[7]……中的数都尽量的大了。但是a[0],a[3],a[6]……中可能有数字小于0,我们让a[0],a[3],a[6]……所有的数字都加上一个最小的数,使所有的数字大于等于0,那么a[1],a[4],a[7]……同时减去一个数,这样便可以求出a[1],a[4],a[7]……的最大值。同理求出a[0],a[3],a[6]……的最大值。……额,说起来挺复杂,看代码吧:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <vector>
using namespace std;

#define LL long long
int aa[111111];
int summ[111111];
int mxx[111111];
int temp[111111];
int *sum;
int *a;
int *mx;

void getVal(int pos)
{
	if(~mx[pos-1]&&~mx[pos-2])
		mx[pos]=sum[pos-1]-mx[pos-1]-mx[pos-2];
	else if(~mx[pos-1]&&~mx[pos+1])
		mx[pos]=sum[pos]-mx[pos-1]-mx[pos+1];
	else
		mx[pos]=sum[pos+1]-mx[pos+1]-mx[pos+2];
}

int main()
{
//	freopen("in.txt","r",stdin);

	sum=&summ[0]+2;
	a=&aa[0]+2;
	mx=&mxx[0]+2;

	int n;
	while(~scanf("%d",&n))
	{
		memset(mxx,-1,sizeof(mxx));
		memset(temp,0,sizeof(temp));

		for(int i=0;i<n;i++) scanf("%d",a+i);
		for(int i=0;i<n;i++) scanf("%d",sum+i);

		mx[2] = sum[1]-sum[0];
		for(int i=5;i<n;i+=3)
			mx[i] = sum[i-1]-sum[i-2]+mx[i-3];

		if(n%3!=2)
		{
			mx[n-3] = sum[n-2]-sum[n-1];
			for(int i=n-6;i>=0;i-=3)
				mx[i] = sum[i+1]-sum[i+2]+mx[i+3];
			for(int i=0;i<n;i++) if(mx[i]==-1)
				getVal(i);
		}
		else
		{
			int pos=-1,val=-1;
			for(int i=0;i<n;i++) if(a[i]!=-1 && i%3!=2)
			{
				pos=i;
				val=a[i];
				break;
			}

			if(pos!=-1)
			{
				mx[pos]=val;
				for(int i=pos+1;i<n;i++) if(mx[i]==-1)
					getVal(i);
				for(int i=pos-1;i>=0;i--) if(mx[i]==-1)
					getVal(i);
			}
			else
			{
				mx[0]=0;
				mx[1]=sum[0];
				val = 0;
				for(int i=3;i<n;i++) if(mx[i]==-1)
				{
					mx[i]=sum[i-1]-mx[i-1]-mx[i-2];
					if(mx[i]<val)
					{
						val=mx[i];
						pos=i;
					}
				}
				for(int i=0;i<n;i+=3)
					temp[i+1]=mx[i+1]+val;
				
				for(int i=0;i<n;i+=3)
				{
					mx[i]=mx[i+1]=-1;
				}

				mx[0]=sum[0];
				mx[1]=0;
				val = 0;
				for(int i=0;i<n;i++) if(mx[i]==-1)
				{
					mx[i]=sum[i-1]-mx[i-1]-mx[i-2];
					if(mx[i]<val)
					{
						val=mx[i];
						pos=i;
					}
				}
				for(int i=0;i<n;i+=3)
				{
					mx[i]+=val;
					mx[i+1]=temp[i+1];
				}
			}
		}

		int m;
		scanf("%d",&m);
		for(int i=0;i<m;i++)
		{
			int t;
			scanf("%d",&t);
			if(a[t]!=-1)
				printf("%d\n",a[t]);
			else
				printf("%d\n",mx[t]);
		}
	}
}
    比赛时代码写的不好看= = 

    然后我做J题时,WJ早就把E题A了。JX和WJ就一直在搞G题。

    听他们简单说了题意(虽然这样说题意不好,但是当时确实没心思看),想了一下和晒素数应该差不多。

    假定a<=b<=c,我们求3个素数和时,保证c和所有可能的a,b和求和。就是说先更新3个素数和,再更新两个素数和,避免重复。要注意的是c+c和c+c+c的情况。乘法亦然。代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <vector>
using namespace std;

#define LL long long
const int maxn = 80001;
bool hash[maxn];
int prime[10000];
LL sum2[maxn];
LL sum3[maxn];
LL mul2[maxn];
LL mul3[maxn];
LL res[maxn];
int Index=0;

void getPrime()
{
	for(int i=2;i<maxn;i++) if(!hash[i])
	{
		prime[Index++]=i;
		for(int j=i+i;j<maxn;j+=i)
			hash[j]=true;
	}
}

void getSum()
{
	for(int i=0;i<Index;i++)
	{
		int pri=prime[i];
		for(int j=0;j<maxn;j++) if(sum2[j])
		{
			if(pri+j>=maxn) break;
			sum3[pri+j]+=sum2[j];
		}

		for(int j=0;j<maxn;j++) if(mul2[j])
		{
			if(pri*j>=maxn) break;
			mul3[pri*j]+=mul2[j];
		}

		for(int j=0;j<=i;j++)
		{
			int temp = pri+prime[j];
			if(temp<maxn)
			{
				sum2[temp]++;
				temp+=pri;
				if(temp<maxn)
					sum3[temp]++;
			}

			LL t = (LL)pri*prime[j];
			if(t<maxn)
			{
				mul2[t]++;
				t*=pri;
				if(t<maxn)
					mul3[t]++;
			}
		}
	}

	for(int i=0;i<maxn;i++) if(mul2[i])
		for(int j=0;j<Index;j++)
		{
			int t=i+prime[j];
			if(t<maxn)
				res[t]++;
		}
}

int main()
{
//	freopen("in.txt","r",stdin);

	getPrime();
	getSum();

	int t;
	while(~scanf("%d",&t))
	{
		LL ans=0;
		ans=mul2[t]+mul3[t]+sum2[t]+sum3[t]+res[t];
		if(!hash[t])
			ans++;
//		cout<<mul2[t]<<" "<<mul3[t]<<" "<<sum2[t]<<" "<<sum3[t]<<" "<<res[t]<<endl;;
		printf("%d\n",ans%1000000007);
	}
}
    算了下答案可能没有超int,不过用LL也不会坏事。

    然后我们三个就A不动了= =。H题题意理解都是问题。

    能力有限,只能继续努力~

    J题代码赛后改进版:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define LL long long
const int maxn = 111111;
int aa[maxn];
int summ[maxn];
int *a=aa+2;
int *sum=summ+2;

void getVal(int i)
{
    if( ~a[i] )
        return;
    if( ~a[i-1] && ~a[i+1])         // 顺序
        a[i]=sum[i]-a[i-1]-a[i+1];
    else if( ~a[i-1] && ~a[i-2])
        a[i]=sum[i-1]-a[i-1]-a[i-2];
    else if( ~a[i+1] && ~a[i+2])
        a[i]=sum[i+1]-a[i+1]-a[i+2];
}

void work(int n)
{
    memset(aa,0,sizeof(aa));

    for(int i=0;i<n;i++) scanf("%d",a+i);
    for(int i=0;i<n;i++) scanf("%d",sum+i);

    for(int i=2;i<n;i+=3) a[i]=sum[i-1]-sum[i-2]+a[i-3];

    if(n%3!=2)
    {
        for(int i=n-3;i>=0;i-=3) a[i]=sum[i+1]-sum[i+2]+a[i+3];
        for(int i=0;i<n;i++) getVal(i);  // 边界
    }
    else
    {
        bool finish = false;
        for(int i=0;i<n;i++) if( ~a[i] )
        {
            if(i%3==2) continue;

            for(int j=i-1;j>=0;j--) getVal(j); // 边界
            for(int j=i+1;j<n;j++)  getVal(j); // 边界
            finish = true;
            break;
        }

        if(!finish)
        {
            a[0] = 0;
            a[1] = sum[0];
            int val = 0;
            int val2 = sum[0];

            for(int i=3;i<n;i+=2)
            {
                a[i]=sum[i-1]-sum[i-2]+a[i-3]; // 不可用getVal函数求
                val = min(a[i],val);

                i++;
                a[i]=sum[i-1]-sum[i-2]+a[i-3];
                val2 = min(a[i],val2);
            }

            for(int i=0;i<n;i+=3)
            {
                a[i]+=val2;
                a[i+1]+=val;
            }
        }
    }

    int m;
    scanf("%d",&m);
    while(m--)
    {
        int t;
        scanf("%d",&t);
        printf("%d\n",a[t]);
    }
}

int main()
{
//    freopen("in.txt","r",stdin);
    int n;
    while( ~scanf("%d",&n) )
        work(n);
}



你可能感兴趣的:(比赛)