A题意(取余最长路):
佳佳有一个n*m的带权矩阵,她想从(1,1)出发走到(n,m)且只能往右往下移动,她能得到的娱乐值为所经过的位置的权的总和。
有一天,她被下了恶毒的诅咒,这个诅咒的作用是将她的娱乐值变为对p取模后的值,这让佳佳十分的不开心,因为她无法找到一条能使她得到最大娱乐值的路径了!
她发现这个问题实在是太困难了,既然这样,那就只在3*n的矩阵内进行游戏吧!
现在的问题是,在一个3*n的带权矩阵中,从(1,1)走到(3,n),只能往右往下移动,问在模p意义下的移动过程中的权总和最大是多少。
n(1<=n<=100000),p(1<=p<=1000000000)。
最简单的思路就是 搞一搞前缀和 枚举两个转折点 那么复杂度是n^2。BOOM!
设三段的前缀和和 分别为s1,s2,s3 设转折点分别为(2,x1) (2,x2)
再仔细想一想p-1肯定是我们能得到的最大值,那么我们可以优化到枚举一个转折点(第二个转折点),前两段的结果丢在set里;
二分就OK了。
但是为了不影响二分的结果,做了一点改动(set不能丢入1,1->2,x1->2,x2)。应丢入1,1->2,x1->2,n 的和
前缀和表示为 s2[n]+s1[x1]-s2[x1-1];
二分的值变为((p-1)-(s3[n]-s3[x2-1])+((s2[n]-s2[x2]))+p)%p,每次更新答案就OK了
再观察一下发现插入和查询的时候都加了s2[n]
所以我们把s2[n]去掉=。=
然后s3[]用的一直是x2->n的和 这里应该用个后缀和的
写的时候手残读入错误,导致以为思路不对 --- 浪费了很多时间 (被自己气笑
PS:啊现在的我们是多么幸福,现成的STL啦啦啦;
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <vector> #include <cstring> #include <set> using namespace std; const int maxn = 1e5+10; typedef long long ll; inline void r(ll&num){ num=0;ll f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); num*=f; } inline void r(int &num){ num=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); num*=f; } ll s1[maxn],s2[maxn],s3[maxn]; int main() { int n; ll p; r(n),r(p); for(int i=1;i<=n;i++) { r(s1[i]); s1[i]=(s1[i]+s1[i-1])%p; } for(int i=1;i<=n;i++) { r(s2[i]); s2[i]=(s2[i]+s2[i-1])%p; } for(int i=1;i<=n;i++) { r(s3[i]); s3[i]=(s3[i]+s3[i-1])%p; } set<ll>s; ll ans = -1; set<ll>::iterator it; ll sum; ll cnt; for(int i=1;i<=n;i++) { s.insert(((s1[i]-s2[i-1])%p+p)%p); sum = (s3[n]-s3[i-1]+s2[i])%p; cnt = ((p-sum)%p+p)%p; it = s.lower_bound(cnt); if(it!=s.begin()) it--; ans = max(ans,((((*it)+sum)+p)%p)); } cout<<ans<<endl; return 0; }
这里有一个小技巧 我们如果想找出小于等于X的最大值 我们只需lower_boundX+1 得到大于等于X+1的区间[it,end) 那么 [begin,it) 就是小于等于X的区间;
if it == begin 不存我们要的值
else *(--it)就是我们要的值辣
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <vector> #include <cstring> #include <set> using namespace std; const int maxn = 1e5+10; typedef long long ll; inline void r(ll&num){ num=0;ll f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); num*=f; } inline void r(int &num){ num=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); num*=f; } ll s1[maxn],s2[maxn],s3[maxn]; int main() { int n; ll p; r(n),r(p); for(int i=1;i<=n;i++) { r(s1[i]); s1[i]=(s1[i]+s1[i-1])%p; } for(int i=1;i<=n;i++) { r(s2[i]); s2[i]=(s2[i]+s2[i-1])%p; } for(int i=1;i<=n;i++) { r(s3[i]); s3[i]=(s3[i]+s3[i-1])%p; } set<ll>s; ll ans = -1; set<ll>::iterator it; ll sum; ll cnt; for(int i=1;i<=n;i++) { s.insert(((s1[i]-s2[i-1])%p+p)%p); sum = (s3[n]-s3[i-1]+s2[i])%p; cnt = ((p-sum)%p+p)%p; it = s.lower_bound(cnt); if(it!=s.begin()) it--; else it = --s.end(); ans = max(ans,((((*it)+sum)+p)%p)); } cout<<ans<<endl; return 0; }
C题意(比大小):
有两个数列A和B 已知A_0,a,b,N A_n=A_(n-1)*a+b (n>=1) B数列满足 B_n=2*B_(n/2) + 1 (n为偶数) B_n=2*B_((n-1)/2) + (n+1)/2 (n为奇数)
现在问B数列的第A_N项和第(A_N)+1项的关系
T组数据 A_0,a,b,N<=1e15
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <vector> #include <cstring> #include <set> using namespace std; typedef long long ll; inline void r(ll&num){ num=0;ll f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); num*=f; } inline void r(int &num){ num=0;int f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); num*=f; } ll a,b,N; ll A0,AN,A; bool flag = false; ll B[40]; void check() { if(flag) { A+=4; } if(B[A]==B[A+1]) { puts("="); } else{ if(B[A]<B[A+1]) { puts("<"); } else{ puts(">"); } } } int main() { int T; r(T); B[0] = -1; //cout<<"-1"<<endl; for(int i=1;i<40;i++) { B[i] = B[i/2]*2+1; if(i&1) { B[i]+=i/2; } //cout<<B[i]<<endl; } while(T--) { flag = false; r(A0),r(a),r(b),r(N); A = A0; for(ll i=1;i<=N;i++) { if(A>4) { flag = true; break; } A = A*a+b; //A%=4; } A = A0%4; N = N > 3 ? N % 4 + 4 : N; for(int i=1;i<=N;i++) { A = A*a+b; A%=4; } check(); } return 0; }