今晚刚搞完的长沙网络赛,在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); }