模擬賽20200218【遞歸/構造,連接字符串最小字典序,帶目標打怪獸】

T1:環

在這裏插入圖片描述
n,l,k100,T10n,l,k\le100,T\le10

題解:

解法一:

  • 觀察B操作相當於把1之間的0的個數其中一個+1,後一個-1,1循環代表0的個數也是循環的。根據循環對應關係畫一畫可以得出0的個數只能有2種,削去小的那部分,剩下的問題轉化爲了子問題(子問題的答案反過來再加上小的部分的0,就是當前0的個數的可行解)。那麼T(n,k)=T(k,(nk)%k)+O(n)T(n,k)=T(k,(n-k)\%k)+O(n),當gcd(k,n)1gcd(k,n)\neq1時無解。
    最後得出第一行之後枚舉循環長度,再枚舉交換的位置,判斷是否可行即可,O(ln2)O(l*n^2)

解法二 在這裏插入圖片描述

Code1:

#include<bits/stdc++.h>
#define maxn 105
using namespace std;
int T,n,k,l,a[maxn][maxn],b[maxn];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
void solve(int n,int k){
	if(k==1) {a[0][0]=1;return;}
	solve(k,n%k);
	for(int i=0;i<k;i++) b[i]=a[0][k-i-1]+(n-k)/k;
	for(int i=0;i<n;i++) a[0][i]=0;
	for(int i=0,sum=0;i<k;i++)
		a[0][i+sum]=1,sum+=b[i];
}
int main()
{
	freopen("circle.in","r",stdin);
	freopen("circle.out","w",stdout);
	scanf("%d",&T);
	while(T--){
		scanf("%d%d%d",&n,&k,&l);
		if(gcd(n,k)!=1) {puts("NO");continue;}
		for(int i=0;i<n;i++) a[0][i]=0;
		solve(n,k);
		for(int i=0;i<l-1;i++)
			for(int t=1;t<n;t++){
				for(int j=0;j<n;j++) a[i+1][(j+t)%n]=a[i][j];
				int num=0,x,y;
				for(int j=0;j<n&&num<=2;j++) if(a[i][j]!=a[i+1][j]){
					num++;
					if(num==1) x=j;
					else y=j;
				}
				if(num==2){
					if(x+1==y&&a[i][x]==1&&a[i][y]==0) break;
					if(x==0&&y==n-1&&a[i][y]==1&&a[i][x]==0) break;
				}
			}
		puts("YES");
		for(int i=0;i<l;i++,putchar('\n'))
			for(int j=0;j<n;j++) putchar(a[i][j]+'0');
	}
}

Code2:

#include <bits/stdc++.h>

using namespace std;

#define REP(i, a, b) for (int i = (a), i##_end_ = (b); i < i##_end_; ++i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define x first
#define y second
#define pb push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()

template<typename T> inline bool chkmin(T &a, const T &b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }

typedef long long LL;

const int oo = 0x3f3f3f3f;

const int maxn = 110;

int n, K, l;

int main()
{
	freopen("circle.in", "r", stdin);
	freopen("circle.out", "w", stdout);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d%d", &n, &K, &l);
		int inv = -1;
		REP(i, 1, n)
			if (K * i % n == 1)
			{
				inv = i;
				break;
			}
		if (~inv)
		{
			puts("YES");
			REP(i, 0, l)
			{
				static int tmp[maxn + 5];
				memset(tmp, 0, sizeof tmp);
				REP(j, 0, K) tmp[(i + j) * inv % n] = 1;
				REP(j, 0, n) printf("%d", tmp[j]);
				printf("\n");
			}
		}
		else puts("NO");
	}
	return 0;
}


T2:DNA序列

在這裏插入圖片描述
n,m50n,m\le50

題解:

首先,如果知道字符串的最優連接順序,那麼我們從後往前枚舉每個字符串的前綴,貪心取最優即可。
在這裏插入圖片描述

Code1(std):

#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
string s[55], x[55], z[55];
int n, idx[55];
bool cmp(int a, int b)
{
	if (x[a] == x[b])
		return z[a] < z[b];
	return x[a] > x[b];
}
int main()
{
	freopen("dna.in", "r", stdin);
	freopen("dna.out", "w", stdout);
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		cin >> s[i];
		x[i] = s[i];
		z[i] = "";
		int t = s[i].length();
		for (int j = 1; j <= t; j++)
		{
			string now = s[i].substr(0, j);
			string res = s[i].substr(j);
			int flg = 0;
			while (1)
			{
				if (now > res)
				{
					flg = 1;
					break;
				}
				if (res.substr(0, j) == now)
					res = res.substr(j);
				else
					break;
			}
			if (!flg)
			{
				x[i] = now;
				z[i] = res;
				break;
			}
		}
		string now = "";
		while (now.size() <= 50)
			now += x[i];
		now = now.substr(0, 50);
		x[i] = now;
		z[i] += 'Z';
	}
	for (int i = 1; i <= n; i++)
		idx[i] = i;
	sort(idx + 1, idx + n + 1, cmp);
	string ans;
	for (int i = 1; i <= n; i++)
	{
		string lst = ans;
		ans = "Z";
		int t = s[idx[i]].size();
		for (int k = 1; k <= t; k++)
			ans = min(ans, s[idx[i]].substr(0, k) + lst);
	}
	cout << ans << endl;
}

還有個非常驚人的超級O(n6)O(n^6)排序貪心,直接枚舉兩個字符串,看交換之後得到的答案是否更優:

#include<bits/stdc++.h>
#define maxn 55
using namespace std;
int n;
string a[maxn],ans;
string solve(){
	string ret;
	for(int i=n;i>=1;i--){
		string now,mn="Z";
		for(int j=0,lim=a[i].size();j<lim;j++)
			now+=a[i][j],mn=min(mn,now+ret);
		ret=mn;
	}
	return ret;
}
int main()
{
	freopen("dna.in","r",stdin);
	freopen("dna.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+1+n);
	ans=solve();
	for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++){
		swap(a[i],a[j]);
		string tmp=solve();
		if(tmp<ans) ans=tmp;
		else swap(a[i],a[j]);
	}
	cout<<ans<<endl;
}

T3:探尋

樹上每個點上有一隻怪獸,打第ii只怪獸會減少aia_i的血量,打完之後會回覆bib_i的血量,要打它必須先打它的父親,在打的過程中必須時刻保證血量0\ge0。問如果要打第xx只怪獸,初始時最少需要多少血量。
n100000,ai,bi109n\le100000,a_i,b_i\le10^9

題解:

解法一:

  • 這題就是這個題加上了一個目標點。
  • 相當於讓bx=+b_x=+\infty,然後要求打完所有怪獸。

解法二:
在這裏插入圖片描述

Code1:

#include<bits/stdc++.h>
#define maxn 200005
#define LL long long
using namespace std;
const LL inf = 1ll<<49;
int n,fa[maxn];
bool del[maxn];
LL a[maxn],b[maxn],ans,sum;
struct cmp{
	bool operator () (const int i,const int j)const{
		bool f1=a[i]<b[i],f2=a[j]<b[j];
		if(f1^f2) return f1;
		if(f1) return a[i]==a[j]?i<j:a[i]<a[j];
		return b[i]==b[j]?i<j:b[i]>b[j];
	}
};
set<int,cmp>S;
int find(int x){return del[fa[x]]?fa[x]=find(fa[x]):fa[x];}
int main()
{
	freopen("prospecting.in","r",stdin);
	freopen("prospecting.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%lld%lld",&fa[i],&b[i],&a[i]);
		if(b[i]==-1) b[i]=1ll<<50;
		S.insert(i);
	}
	for(int x;sum<inf;S.erase(x),del[x]=1)
		if(!find(x=*S.begin())){
			ans=min(ans,sum-a[x]);
			sum+=-a[x]+b[x];
		}
		else{
			S.erase(fa[x]);
			a[fa[x]]+=max(a[x]-b[fa[x]],0ll);
			b[fa[x]]=b[x]+max(b[fa[x]]-a[x],0ll);
			S.insert(fa[x]);
		}
	printf("%lld\n",-ans);
}

Code2(std):

#include <bits/stdc++.h>

using namespace std;

#define REP(i, a, b) for (int i = (a), i##_end_ = (b); i < i##_end_; ++i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define x first
#define y second
#define pb push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()

template<typename T> inline bool chkmin(T &a, const T &b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }

typedef long long LL;

const int oo = 0x3f3f3f3f;

const int __buffsize = 100000;
char __buff[__buffsize];
char *__buffs, *__buffe;

#define getc() (__buffs == __buffe ? fread(__buff, 1, __buffsize, stdin), __buffe = __buff + __buffsize, *((__buffs = __buff)++) : *(__buffs++))

template<typename T> inline T &Read(T &x)
{
	static char c;
	while (1) 
	{ 
		c = getc(); 
		if (c == '-' || (c >= '0' && c <= '9')) break; 
	}
	bool flag = c == '-';
	x = flag ? 0 : c - '0';
	while (1)
	{
		c = getc();
		if (c < '0' || c > '9') break;
		(x *= 10) += c - '0';
	}
	if (flag) x = -x;
	return x;
}

#undef getc

const int maxn = 200100;
const LL maxsum = 1e17;

int n;
vector<int> children[maxn + 5];
LL gain[maxn + 5];
LL loss[maxn + 5];
int fa[maxn + 5];

multiset<pair<LL, LL> > all[maxn + 5];

void dfs(int x)
{
	for (auto y : children[x])
	{
		dfs(y);
		if (SZ(all[y]) > SZ(all[x])) swap(all[x], all[y]);
		for (auto u : all[y]) all[x].insert(u);
		all[y].clear();
	}
	LL cur_invest = loss[x], cur_profit = gain[x] - loss[x];
	while (!all[x].empty() && (cur_profit <= 0 || cur_invest + cur_profit >= all[x].begin()->x))
	{
		auto tmp = all[x].begin();
		cur_invest += max(0ll, tmp->x - (cur_invest + cur_profit));
		cur_profit += tmp->y;
		all[x].erase(tmp);
	}
	if (cur_profit > 0) all[x].insert(mp(cur_invest, cur_profit));
}

int main()
{
	freopen("prospecting.in", "r", stdin);
	freopen("prospecting.out", "w", stdout);
	Read(n);
	loss[0] = maxsum;
	REP(i, 1, n) 
	{
		Read(fa[i]);
		Read(gain[i]);
		Read(loss[i]);
		children[fa[i]].pb(i);
		if (!~gain[i]) gain[i] = maxsum * 2;
	}
	dfs(0);
	printf("%lld\n", all[0].begin()->x - maxsum);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章