AGC 049 部分簡要題解


nmd 差1分鍾過 E,真就老年選手不配進第一頁/ll

A

計算每個點的貢獻,做完了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 110;

string s[N];
int n;

bitset<N> tow[N];

int main()
{
	cin >> n;
	for(int i=0;i<n;i++)cin >> s[i],tow[i][i]=1;
	for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(s[i][j]=='1')tow[j][i]=1;
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++)for(int k=0;k<n;k++){
			if(tow[j][i] && tow[i][k])tow[j][k] = 1;
		}
	}
	typedef double db;
	db ans = 0;
	for(int i=0;i<n;i++){
		int p = tow[i].count();
		// cout << p << endl;
		ans += (db)1/(db)p;
	}
	// cout << ans << endl;
	printf("%.20lf",ans);
}

B

可以看作是移動所有 1。先貪心找 t 中每個 1 從哪里移動過來可以證明正確。

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;

inline int readc(){
	char x=0;while(!isdigit(x))x=getchar();
	return x-'0';
}

int s[N], t[N], n;
int ss,tt;
int f=0;

int main()
{
	cin >> n;
	for(int i=1;i<=n;i++)s[i]=readc(),ss++;
	for(int i=1;i<=n;i++)t[i]=readc(),tt++;
	if(ss<tt||ss%2!=tt%2){puts("-1");exit(0);}
	long long ans=0;
	for(int i=1;i<=n;i++){
		if(t[i])++f,ans-=i;
		if(s[i] && f)--f,ans+=i,s[i]=0;
	}
	if(f){puts("-1");exit(0);}
	for(int i=1;i<=n;i++){
		if(s[i]){
			f^=1;
			if(f)ans-=i;
			else ans+=i;
		}
	}
	cout << ans << endl;
}

C

判斷的話是對於每個位置計算 \(a_i - b_i\),如果 \(<0\) 一定有一個 \(aj - b_j\ge 0(j\ge i)\) 的小於等於 \(a_i\)(考慮一個位置如果一定要被刪除那么其實可以不考慮這個位置刪除了誰,因為一定可以看作另外一個刪除了它。

你移動一個可以弄一個 \(a_{i}+1, 1\) 出來,把 \(a_i\) 安排掉,或者直接把一個 \(a_i-b_i\) 取到 \(\ge 0\),之后暴力就行。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
typedef pair<int,int> pii;
int n;
int a[N], b[N], lst[N];

vector<pii> Vec;
vector<int> vec2;

int main()
{
	cin >> n;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)scanf("%d",&b[i]);
	int last = a[n]+1;
	vector<int> cost;
	for(int i=n;i;i--){
		lst[i] = a[i] - b[i];
		// cout << lst[i] << ":" << last << endl
		if(lst[i]>0)last = min(last, lst[i]);
		else if(last <= a[i]){
			vec2.push_back(a[i]),Vec.push_back(pii(last,1-lst[i])),cost.push_back(0);
		}
		else {
			// cout << i << ":" << lst[i] << "::" << last << endl;
			vec2.push_back(a[i]),Vec.push_back(pii(last,1-lst[i]));
			cost.push_back(1);
		}
	}
	reverse(Vec.begin(),Vec.end());
	reverse(vec2.begin(),vec2.end());
	reverse(cost.begin(),cost.end());
	if(Vec.empty()){
		puts("0");
	}else{
		int ans = 0x3f3f3f3f;
		for(int i=(int)Vec.size()-1;~i;i--){
			if(i+1<(int)Vec.size())cost[i]+=cost[i+1];
		}
		
		for(int i=-1;i<(int)Vec.size();++i){
			int w=0;
			if(i!=-1)w=Vec[i].second;
			if(i+1<(int)Vec.size()){
				w=max(w, cost[i+1]);
			}
			// cout << i << ":" << w << endl;
			ans = min(ans, w);
		}
		cout << ans << endl;
	}
}

D

相當於是要求它是下凸的。

考慮分成斜率 \(>0,=0,<0\) 三個部分。
對於 \(1,3\) 部分,我們考慮斜率的差分:\(f[i][j]\) 表示 \(i\) 個數,和是 \(j\) 的結果。如果這個位置的斜率是 \(t\)(這個時候后面全部要斜率 \(+t\)),會增加 \(t*i*(i-1)/2\),暴力dp即可(第一維只有根號)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
/* math */
int n,m;
int dp[450][100010], f[450][100010], g[450][100010];

int main()
{
	cin >> n >> m;
	dp[1][0]=f[1][0]=g[1][0]=1;
	int mx=1;
	for(int i=1;i*(i-1)/2<=m;i++){
		mx=i;
		if(i>1){
			int A = i*(i-1)/2;//1+2+..+i-1
			for(int j=0;j<=m;j++){
				if(j>=A)dp[i][j] = add(dp[i-1][j-A], dp[i][j-A]);
				f[i][j] = dp[i][j];
			}
		}
		for(int j=0;j<=m;j++){
			dp[i][j]=add(dp[i][j],dp[i-1][j]);
			g[i][j]=dp[i][j];
			if(j>=n)g[i][j]=add(g[i][j],g[i][j-n]);
		}
	}
	int ans=0;
	// cout << mx << endl;
	for(int i=1;i<=min(n,mx);i++){
		int i2 = n+1-i;
		i2=min(i2,mx);
		for(int j=0;j<=m;j++){
			// cout << i << ":" << j << "::" << f[i][j] << ":" << g[i2][m-j] << endl;
			ans=add(ans, mul(f[i][j],g[i2][m-j]));
		}
	}
	cout << ans << endl;
}

E

考慮原問題可以轉化成:

給一個二維的矩陣,其中 \(\forall_{1\le i\le f_k} G(k,i) = 1\)。每次可以單點異或 \(1\) 或者一行顏色相同的異或 \(1\),代價分別是 \(1\) 或者 \(C\)

於是原問題轉化成了 \(O(nk)\)\(B_{i,j} = \{0,1\}\) 的問題。

考慮 \(B \in \{0,1\}\) 如何求解最大值的計數。

首先對於這種情況預先算出全部都是用區間操作的貢獻。

現在相當於是要對若干位置改成單點操作,顯然一段極長的區間要么全部操作,要么全部不操作,同樣不可能同時操作兩個相鄰的區間(這樣顯然一邊不操作不會變劣)。

那么現在實際上有一個 \(O(n)\) dp:記錄所有不相等位置 \(p\)\(f[i] = \max(f[i-1], p_i - p_{i-1} - C + f[i-2])\)

考慮兩種轉移的差,不難發現每次遇到一個連續相等的差會 \(+1\),遇到不相等的則根據差的正負重新算差,並且這個差的絕對值 \(\le n\)

將兩種轉移的差記錄下來作為狀態,dp 值分別記錄方案數以及 dp 值之和即可。

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
/* math */
const int N = 55,S=N;
int n,c,k;
int b[N][N];
int w[2][N];
vector<int> v;

int dp[N][2][N*2],g[N][2][N*2];
inline int query(){
	memset(dp, 0, sizeof dp);
	memset(g, 0, sizeof g);
	int v=1;
	int all = 1;
	w[0][0]=1;
	w[0][n+1]=1;
	for(int i=0;i<=n;i++){
		all = mul(all, add(w[0][i], w[1][i]));
	}
	int S0 = 0;
	for(int i=1;i<=n;i++){
		int ww = mul(all, mul(qpow(add(w[0][i],w[1][i]),mod-2),qpow(add(w[0][i-1],w[1][i-1]),mod-2)));
		// cout << ww << endl;
		S0 = add(S0, mul(ww,mul(w[0][i-1],w[1][i])));
	}
	S0 = mul(S0, c);
	// cout << S0 << endl;
	for(int i=1;i<=n+1;v=mul(v,w[0][i++])){
		// cout << i << "::" << v << "," << w[0][i] << " " << w[1][i] << endl;
		dp[i][1][c+S]=v,g[i][1][c+n*n]=0;
		for(int j=S-n;j<=S+n;j++){
			int sum = j-S-1;
			for(int k=0;k<2;k++){
				dp[i][k][S+sum] = add(dp[i][k][S+sum],dp[i-1][k][j]);
				g[i][k][S+sum] = add(g[i][k][S+sum],g[i-1][k][j]);
				if(sum>0){
					dp[i][k^1][S-sum+c] = add(dp[i][k^1][S-sum+c],dp[i-1][k][j]);
					g[i][k^1][S-sum+c] = add(g[i][k^1][S-sum+c],g[i-1][k][j]);
					// cout << i << ":" << sum << endl;
					g[i][k^1][S-sum+c] = add(g[i][k^1][S-sum+c],mul(dp[i-1][k][j],sum));
				}else{
					dp[i][k^1][S+c] = add(dp[i][k^1][S+c],dp[i-1][k][j]);
					g[i][k^1][S+c] = add(g[i][k^1][S+c],g[i-1][k][j]);
					g[i][k^1][S+c] = add(g[i][k^1][S+c],mul(dp[i-1][k][j],0));
				}
			}
		}
		for(int j=S-n;j<=S+n;j++){
			for(int k=0;k<2;k++){
				dp[i][k][j] = mul(dp[i][k][j], w[k][i]);
				g[i][k][j] = mul(g[i][k][j], w[k][i]);
				// if(dp[i][k][j])cout << i << ":" << k << ":" << j-S << "::" << dp[i][k][j] << ":" << g[i][k][j] << endl;
			}
		}
	}
	int ans = 0;
	for(int i=n+1;i<=n+1;i++){
		for(int j=S-n;j<=S+n;j++){
			ans = add(ans, g[i][0][j]);
			ans = add(ans, g[i][1][j]);
		}
	}
	// cout << S0 << ":" << ans << endl;
	// cout << ans << endl;
	// system("pause");
	return sub(S0, ans);
}

int main()
{
	cin >> n >> c >> k;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=k;j++){
			cin >> b[i][j];
			v.push_back(b[i][j]);
		}
	}
	v.push_back(0);
	sort(v.begin(), v.end());
	int ans = 0;
	for(int t=0;t<n*k;t++)if(v[t]!=v[t+1]){
		// cout << v[t] << " to " << v[t+1] << endl;
		for(int i=1;i<=n;i++){
			w[0][i] = w[1][i] = 0;
			for(int j=1;j<=k;j++){
				if(b[i][j]>=v[t+1])w[1][i]++;
				if(b[i][j]<=v[t])w[0][i]++;
			}
			// cout << w[0][i] << ":" << w[1][i] << endl;
		}
		int W = query();
		ans = add(ans, mul(W, v[t+1]-v[t]));
	}
	cout << ans << endl;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM