网络赛好难。。 看半天一题都写不出来。。
C HDU 6440
题意:给出质数p,定义运算加与乘,使得(m+n)p=mp+np成立,且存在0<q<p,使得集合{qk|0<q<p}与集合{k|0<q<p}相等。
思路:由费马小定理可知,对于质数p,有ap-1 ≡ 1(mod p),
于是有(m+n)p ≡ m+n(mod p),mp ≡ m(mod p),np ≡ n(mod p),
所以原来的加法乘法基础上模p即可。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int main() { int i,j,T,p; scanf("%d",&T); while (T--) { scanf("%d",&p); for (i=0;i<p;i++) { for (j=0;j<p;j++) printf("%d ",(i+j)%p); printf(" "); } for (i=0;i<p;i++) { for (j=0;j<p;j++) printf("%d ",i*j%p); printf(" "); } } return 0; }
D HDU 6441
题意:给出n,a,求正整数b,c使得an+bn=cn。
思路:由费马大定理可知,an+bn=cn在n>2时无正整数解。
于是对于n>2和n==0的情况输出无解,对于n==1的情况输出1 a+1,对于n==2的情况构造勾股数。
构造勾股数:当a==2n+1,有b=2n2+2n,c=2n2+2n+1,使得a2+b2=c2;
当a==2n,有b=n2-1,c=n2+1,使得a2+b2=c2。(n为正整数)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int main() { int T,n,a; ll x; scanf("%d",&T); while (T--) { scanf("%d%d",&n,&a); if (n>2 || n==0) printf("-1 -1 "); else if (n==1) printf("%d %d ",1,a+1); else { x=a/2; if (a&1) printf("%lld %lld ",2*x*x+2*x,2*x*x+2*x+1); else printf("%lld %lld ",x*x-1,x*x+1); } } return 0; }
G HDU 6444
题意:给一个n长的环,从位置i走一步就走到位置(i+k)%n,每走到一个格子i就能得到价值a[i],最多走m步。初始时可以从任意位置开始。问要想最后的总价值不小于s,那么出发时的初始价值最小为多少。
思路:(这题我能WA10多次,调两晚上,就TM离谱)
很明显走的路线是一个环。
对于每一个格子求出它所在的环的路线,设路线长度为cnt,求出路线价值的前缀数组sum。
假设solve(x)求的是sum中区间长度不超过x的最大区间和。
(这个可以用单调队列实现,好像也有其他方法,不过说起来list是真方便)
若sum[cnt]<=0,那么此时的所能从格子中得到的最大价值就是solve(min(cnt,m))。
若sum[cnt]>0,分两种情况讨论。
1、若m<cnt,即m/cnt==0。此时的最大价值就是solve(m)。
2、若m>=cnt,即m/cnt>0。此时的最大价值有两种可能。
一种是走m/cnt个整圈,再走m%cnt步,最大价值就是(m/cnt)*sum[cnt]+solve(m%cnt);
另一种是走m/cnt-1个整圈,再走cnt步,最大价值就是(m/cnt-1)*sum[cnt]+solve(cnt)。
最后,输出max(0,s-ans)即可。
#include<cstdio> #include<cstring> #include<list> #include<algorithm> using namespace std; typedef long long ll; const int maxn=10005; int vis[maxn]; ll a[maxn],g[maxn],sum[maxn<<1],cnt; list<ll>q; ll solve(int m) { if (m==0) return 0; q.clear(); q.push_back(0); ll re=0; for (int i=1;i<=2*cnt;i++) { while (!q.empty() && sum[q.back()]>sum[i]) q.pop_back(); q.push_back(i); while (!q.empty() && i-q.front()>m) q.pop_front(); re=max(re,sum[i]-sum[q.front()]); } return re; } int main() { int i,j,t,T; ll n,m,k,s,ans,div,res; scanf("%d",&T); for (t=1;t<=T;t++) { scanf("%lld%lld%lld%lld",&n,&s,&m,&k); for (i=0;i<n;i++) { scanf("%lld",&a[i]); vis[i]=0; } ans=0; for (i=0;i<n;i++) { if (vis[i]) continue; cnt=0; for (j=i;vis[j]==0;j=(j+k)%n)//循环节上的所有元素 { vis[j]=1; g[++cnt]=a[j]; } sum[0]=0; for (j=1;j<=cnt;j++) sum[j]=sum[j-1]+g[j]; for (j=1;j<=cnt;j++) sum[j+cnt]=sum[j]+sum[cnt];//前缀和 if (sum[cnt]<=0) ans=max(ans,solve(min(m,cnt))); else { div=m/cnt; res=m%cnt; ll mx1=solve(cnt); ll mx2=solve(res); if (div>0) { ans=max(ans,(div-1)*sum[cnt]+mx1); ans=max(ans,div*sum[cnt]+mx2); } else ans=max(ans,mx2); } } if (s-ans>0) ans=s-ans; else ans=0; printf("Case #%d: %lld ",t,ans); } return 0; }
J HDU 6447
题意:给一个1e9*1e9的地图,从(0,0)出发,走到(1e9,1e9),每次只能走(1,0),(0,1)或(1,1)。地图上有n个(n<=1e5)宝物,第i个宝物有价值w[i]。若宝物在(x,y),只能从(x-1,y-1)走才能获得这个宝物。问能够获得的宝物的最大总价值。
思路:用dp[i][j]表示走到当前格子所能获得的最大价值,可以想到DP公式dp[i][j]=max(dp[i-1][j],dp[i-1][j],dp[i-1][j-1]+w),
直接做复杂度不对,应该想到用数据结构优化。
首先将宝物坐标x离散化,接着按照y的大小为宝物排序。
对于每个宝物,查询所有x比它小的宝物(因为已经按y排过序,y也比它小)的dp中的最大值mx,
用mx+w更新答案,然后更新dp[x]=mx+w。
明显这维护的是一个区间最大值(以离散化后的x为下标),使用树状数组或者线段树都可以。
(然而我线段树写挂了,也不知道为什么。。)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100005; int c[maxn],n; struct node { int x,y,w; }e[maxn]; bool cmp1(node a,node b){return a.x<b.x;} bool cmp2(node a,node b) { if (a.y==b.y) return a.x>b.x; return a.y<b.y; } int lowbit(int x){return x&(-x);} void update(int x,int val) { for (int i=x;i<=n;i+=lowbit(i)) c[i]=max(c[i],val); } int query(int x) { int i,re=0; for (i=x;i;i-=lowbit(i)) re=max(re,c[i]); return re; } int main() { int i,j,T,last,cnt,tmp,ans; scanf("%d",&T); while (T--) { scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w); last=-1; cnt=0; sort(e+1,e+n+1,cmp1); for (i=1;i<=n;i++) { if (e[i].x==last) e[i].x=cnt; else e[i].x=++cnt; last=e[i].x; } sort(e+1,e+n+1,cmp2); memset(c,0,sizeof(c)); ans=0; for (i=1;i<=n;i++) { tmp=query(e[i].x-1)+e[i].w; ans=max(ans,tmp); update(e[i].x,tmp); } printf("%d ",ans); } return 0; }