题解 [REOI-p1] 打捞

传送门

日常签不上到。
日常 普及- 做一年然后高时间复杂度高实现复杂度艹过去。

先说我的垃圾做法:
定义序列 \(b_k(i, j)=(a_{i,k}', a_{j, k}')\)
根据题面中 \(a'\) 定义知 \(b(i, j)\) 有循环节 \(t=\operatorname{lcm}(l_i, l_j)\)
又有 \(\forall i\in [1, n], l_i\leqslant 10^3\)
所以有一个直接枚举点对然后 \(O(\rm lcm)\) 算的做法,复杂度上界是 \(O(n^2V^2)\)
\(V\)\(l_i\) 的取值范围上界
然后发现这yang

艹这好像是个假做法
选择多个较大且不互质的数好像就能卡
复杂度是 \(O(\sum\limits_{l_i, l_j}\rm lcm(l_i, l_j))\) 的,注意是枚举的本质不同区间长度对
鸽了鸽了

正解
该描述的官方题解里都描述出来了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 3000010
#define pb push_back
#define ll long long
#define int128 __int128
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k;
vector<ll> a[N];
ll t1[N], t2[N], ans;
const ll mod=998244353;

signed main()
{
	n=read(); k=read();
	for (int i=1; i<=n; ++i) {
		int t=read();
		for (int j=1; j<=t; ++j) a[i].pb(read());
	}
	sort(a+1, a+n+1, [](const vector<ll>& a, const vector<ll>& b){return a.size()<b.size();});
	for (int i=1; i<=n; ++i) {
		int len1=a[i].size(), lst=0;
		for (int j=i+1; j<=n; ++j) {
			int len2=a[j].size();
			if (len2!=lst) {
				int lcm=len1/__gcd(len1, len2)*len2, now;
				ll d=k/lcm;
				for (int k=1; k<=len2; ++k) t1[k]=0;
				now=0;
				for (int k=1; k<=lcm/len1; ++k)
					for (auto& it:a[i]) t1[(now++)%len2+1]+=it*d;
				now=0;
				for (int t=1; t<=k%lcm; ++t)
					t1[(now++)%len2+1]+=a[i][(t-1)%len1];
				for (int k=1; k<=len2; ++k) t1[k]%=mod;
				lst=len2;
			}
			ll sum=0;
			for (int k=1; k<=len2; ++k) sum=(sum+t1[k]*a[j][k-1])%mod;
			// cout<<"sum: "<<sum<<endl;
			ans=max(ans, sum);
		}
	}
	// for (int i=1; i<=n; ++i) {
	// 	for (int j=i+1; j<=n; ++j) {
	// 		int len1=a[i].size(), len2=a[j].size();
	// 		int lcm=len1/__gcd(len1, len2)*len2, now;
	// 		now=0;
	// 		for (int k=1; k<=lcm/len1; ++k)
	// 			for (auto& it:a[i]) t1[++now]=it;
	// 		now=0;
	// 		for (int k=1; k<=lcm/len2; ++k)
	// 			for (auto& it:a[j]) t2[++now]=it;
	// 		ll d=k/lcm, sum=0;
	// 		for (int k=1; k<=lcm; ++k) sum=(sum+t1[k]*t2[k]%mod*d)%mod;
	// 		for (int t=1; t<=k%lcm; ++t) sum=(sum+t1[t]*t2[t])%mod;
	// 		ans=max(ans, sum);
	// 	}
	// }
	cout<<(ll)(ans%mod)<<endl;

	return 0;
}
posted @ 2022-08-01 21:33  Administrator-09  阅读(1)  评论(0编辑  收藏  举报