您的位置:首页 > 其它

简记2013 ACM/ICPC Asia Regional Changsha Online

2013-09-22 22:40 393 查看
    今晚刚搞完的长沙网络赛,在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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  比赛