BZOJ 4488:[Jsoi2015]最大公约数 UPC:2018山东冬令营 权值 (GCD)
提交: 57 解决: 19
[提交][状态][讨论版][命题人:admin]
题目描述
给定一个长为n的正整数序列Ai。对于它的任意一个连续的子序列{Al, Al+1, ..., Ar},定义其权值W (l, r)为其长度与序列中所有元素的最大公约数的乘积,即W (l, r) = (r − l + 1) × gcd(Al, Al+1, .., Ar )。
你需要输出权值最大的子序列的权值
你需要输出权值最大的子序列的权值
输入
第一行一个正整数n。
第二行n个正整数,表示序列Ai。
第二行n个正整数,表示序列Ai。
输出
一行一个正整数,表示答案。
样例输入
5
30 60 20 20 20
样例输出
80
提示
最后四个元素形成的子序列权值最大。
对于前30%的数据:n ≤ 2000
对于所有数据:1 ≤ n ≤ 105,1 ≤ Ai ≤ 109
来源
【思路】
有一个定理 : 长度为n的子序列中 , GCD 最多为log(n)
在 BZOJ 上 这个 时间限度时 10s 在 upc 上 限定1s ;
很尬尬的用 Map 数组, 在bzoj上跑1s 在 upc 上 跑1092ms 差一丢丢 就是过不去;
改用数组标记 时间 降到128ms , 说明UPC 对 STL 库 的支持 不是很好哇;
固定右端点(枚举右端点) 去掉重复的 gcd , 延伸最左端点能达到最长;
map 的话 不断翻滚, 数组 是去重
【代码实现】
STL map的‘
#include <iostream> #include <bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) typedef long long ll; const ll INF=0x3f3f3f3f; const int MAXN=1e5+5; const int MOD=1e9+7; using namespace std; inline ll gcd(ll a,ll b) { return b? gcd(b,a%b):a;} ll a[MAXN]; map<ll,ll>mp,tmp; map<ll,ll>::iterator it; int main() { int n; ll ans=-INF; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=1;i<=n;i++) { ans=max(ans,a[i]); for(it=mp.begin();it!=mp.end();it++) { ll now_gcd = gcd(it->first,a[i]); ans= max(ans, now_gcd*(i-it->second+1)); if(!tmp[now_gcd]) tmp[now_gcd]=(it->second); else tmp[now_gcd]= min(tmp[now_gcd],it->second); // 取left最远 } if(!tmp[a[i]]) tmp[a[i]]=i; mp=tmp; tmp.clear(); } printf("%lld",ans); return 0; }
用数组标记的 128ms
#include <iostream> #include <bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) typedef long long ll; const ll INF=0x3f3f3f3f; const int MAXN=1e5+5; const int MOD=1e9+7; using namespace std; inline ll gcd(ll a,ll b) { return b? gcd(b,a%b):a;} ll col[MAXN]; ll gc[MAXN]; ll a[MAXN]; map<ll,ll>mp,tmp; map<ll,ll>::iterator it; int main() { int n; ll ans=-INF; int k=0,cot; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=1;i<=n;i++) { col[++k]=i; gc[k]=a[i]; for(int j=k-1;j>=1;j--) gc[j]=gcd(gc[j],gc[j+1]); int cot=0; for(int j=1;j<=k;) { gc[++cot]=gc[j]; col[cot]=col[j]; while(gc[cot]==gc[j]) j++; } k=cot; for(int j=1;j<=k;j++) { ans=max(ans,gc[j]*(i-col[j]+1)); } } printf("%lld",ans); return 0; }
123
岂曰无衣?与子同袍。王于兴师,修我戈矛。与子同仇!
岂曰无衣?与子同泽。王于兴师,修我矛戟。与子偕作!
岂曰无衣?与子同裳。王于兴师,修我甲兵。与子偕行!