1. 程式人生 > 其它 >2021CCPC網路選拔賽 (unrated)部分題目

2021CCPC網路選拔賽 (unrated)部分題目

1002-Time-division Multiplexing

題意:
給定你\(n\)個長度小於\(12\)的字串,然後迴圈的構造一個無限長都的字串\(s\),構造方式為依次從\(1-n\)的串中取出一個一個字元,如兩個字串長度為\(3,2\),那麼\(s\) = \(t_{11}t_{21}t_{12}t_{22}t_{13}t_{21}t_{11}t_{22}t_{12}t_{21}t_{13}t_{22}\ \ \ t_{11}t_{21}\),問你能包含\(n\)個字串中出現的所有字元的最小長度的子串長度為多少

思路:
會發現經過某個長度後\(s\)就會重複,那麼這個長度是多少呢,手寫幾個例子會發現等於\(n\)

個字串的\(LCM*n\),但是這樣考慮還不行,因為串是無限長度,所以需要把串長再乘\(2\)才會得到不遺漏的\(s\)的一個模式串,然後我們就只需要在迴圈節長度\(*2\)的這個串上做尺取就可以得到我們想要的答案了。

複雜度因為\(lcm(2,3,4,7,8,9,10,11,12) = 27720\),所以串長最多也就是\(5.5e6\),再加上雙指標\(O(n)\)的掃一遍,時間正好。

\(hdoj\)噁心壞了,寫完了交不上去......

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 2e7 + 10;
char s[N];
char t[110][20];
int len[110];
int n,cnt[30],tot,vis[30];

int gcd(int a,int b) {
	return b == 0 ? a : gcd(b,a%b);
}

void solve() {
	tot = 0;
	for(int i = 0;i < 26;i ++) vis[i] = cnt[i] = 0;
	scanf("%d",&n);
	getchar();
	for(int i = 1;i <= n;i ++) {
		scanf("%s",t[i]+1);
		len[i] = strlen(t[i]+1);
	}
	for(int i = 1;i <= n;i ++) {
		for(int j = 1;j <= len[i];j ++) {
			if(!vis[t[i][j]-'a']) {
				vis[t[i][j]-'a'] = 1;
				tot++;
			}
		}
	}
	int lcm = len[1];
	for(int i = 2;i <= n;i ++) {
		lcm = lcm * len[i] / gcd(lcm,len[i]);
	}
	lcm *= n;
	int id = 1,round = 1;
	for(int i = 1;i <= lcm;i ++) {
		if(id > n) {
			id = 1; round++;
		}
		s[i] = t[id][(round-1)%len[id]+1];
		id++; 
	}
	for(int i = lcm + 1;i <= lcm * 2;i ++) {
		s[i] = s[i-lcm];
	}
	lcm *= 2;
	s[lcm+1] = '\0';
	int mi = INF;
	int now = 0;
	for(int st = 1,ed = 1;st <= lcm;) {
		if(ed <= lcm && now < tot) {
			while(ed <= lcm && now < tot) {
				if(cnt[s[ed]-'a'] == 0) {
					now++;
				}
				cnt[s[ed]-'a']++;
				ed++;
			}
		}
		if(now == tot) {
			mi = min(mi,ed - st);
		}
		cnt[s[st]-'a']--;
		if(cnt[s[st]-'a'] == 0) now--;
		st++;
	}
	printf("%d\n",mi);
}

int main() {
	int T;scanf("%d",&T);
	while(T--) solve();
	return 0;
}

1007-Function

題意:

思路:
可以發現\(g(x)_{max} = g(99999) = 54\),所以\(g(x)\)至多\(54\)個不同的值,那麼當\(g(x)的值確定之後\),這個函式的圖形就是一個二次函式的一些不連續的點(因為不是所有的\(x \ g(x)\) = 當前列舉的值)
所以直接列舉\(g(x)\)的值,然後分類討論這個二次函式的影象的樣子,\(a=0,a<0,a>0\)即可確定函式的最小值。
預處理出來\(g(x)\)=列舉值的\(x\)有哪些,每次找最值只需要在其中二分即可,但是對稱軸位置處可能不存在\(x\),所以我們只需要二分第一個\(\ge \ x\)

的位置,和它前面的位置去這兩個位置處的最小值即可(\(a>0\)的情況)

有一個小細節就是我們預處理的是\(1 - 1000000\)的值,但是每次會給出一個N來固定上限,所以每次對於一個特定的\(N\)來說,要確定一個上界,二分或者直接取邊界的操作都不能直接超過這個上界

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-6;
const int N = 60;
std::vector<ll>vec[N];

ll cal(ll x) {
	ll sum = 0;
	while(x) {
		sum += x % 10;
		x /= 10;
	}
	return sum;
}

void solve() {
	ll ans = INF;
	ll A,B,C,D,N;
	scanf("%lld%lld%lld%lld%lld",&A,&B,&C,&D,&N);
	//f(x) = Ax^2g(x) + Bx^2 + Cxg(x)^2 + Dxg(x)
	//(Ag(x) + B)x^2 + (Cg(x)^2 + Dg(x))x
	for(ll i = 1;i <= 54;i ++) {
		if(sz(vec[i]) == 0 || vec[i][0] > N) continue;
		ll a = A * i + B,b = C * i * i + D * i;
		ll r = upper_bound(vec[i].begin(),vec[i].end(),N) - vec[i].begin();
		//因為預處理的是1-1e6,這是一個wa點
		if(a <= 0) {
			ll j1 = vec[i][0];
			ll j2 = vec[i][r-1];
			ans = min(ans,min(a * j1 * j1 + b * j1,a * j2 * j2 + b * j2));
		}
		else if(a > 0) {
			ll mid = b / (-2 * a);
			std::vector<ll>::iterator j1 = lower_bound(vec[i].begin(),vec[i].begin() + r,mid),j2;
			if(j1 == vec[i].begin() + r) {//處理一個找不到的情況
				j1 = j2 = prev(j1);
			}
			else {
				if(j1 == vec[i].begin()) j2 = j1;
				else j2 = prev(j1);
			}
			ll x1 = *j1,x2 = *j2;
			ans = min(ans,min(a * x2 * x2 + b * x2,a * x1 * x1 + b * x1));
		}
	}
	printf("%lld\n",ans);
}

int main() {
	for(ll i = 1;i <= 1000000;i ++) {
		vec[cal(i)].pb(i);
	}
	int T;scanf("%d",&T);
	while(T--) solve();
	return 0;
}