3月6日被虐记录

D - ABC Transform

题意:

给定一个包含ABC的字符串,对于每一次扩展,一个字符会变为两个字符。
A →BC, B →CA, C →AB.
Q次询问,扩展ti次之后,第ki个字符是什么?
Q ≤10^5, ti<10^18, ki<min(1e18, the length of S(t))

思路:

对于较高的层数来说,每次找到其来时的路径,就像一个完全二叉树,对于当前层数的第x个节点,其父节点是上一层的第x/2(上取整)个。
因为x不会超过1e18,所以照这样每次除2,不超过64次就会变为1。变为1之后,其祖先节点都会是1,因为第1个位置有循环性,所以直接取模看当前节点是什么,然后按着路径再回去。

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m, k;
char a[N];
int b[N];

signed main(){
	Ios;
	cin>>a+1;
	n = strlen(a+1);
	
	mp['A'] = {'B', 'C'}, mp['B'] = {'C', 'A'}, mp['C'] = {'A', 'B'};
	
	cin>>m;
	while(m--)
	{
		int floor, cnt;
		cin>>floor>>cnt;
		
		int id;
		if(floor>=60) id=1;
		else
		{
			int x = 1ll<<floor;
			id = (cnt+x-1)/x;
			if(cnt%x==0) cnt=x;
			else cnt%=x;
		}
		
		int t=0;
		while(cnt!=1)
		{
			b[++t] = cnt%2;
			cnt = (cnt+1)/2;
			floor--;
		}
		
		char st;
		if(floor%3==0) st = a[id];
		if(floor%3==1){st = char(a[id]+1);if(st=='D') st='A';}
		if(floor%3==2){st = char(a[id]+2);if(st=='D') st='A';if(st=='E') st='B';}
		
		for(int i=t;i>=1;i--)
		{
			if(b[i]==0) st = mp[st].se;
			else st = mp[st].fi;
		}
		cout << st << endl;
	}
	
	return 0;
}

D. Make Them Equal

题意:

给定长度为 n(1 ≤n ≤10^3) 的数组 a,初始全为 1,可以经过最多 k 次操作:
对于一个 i,选择一个 x,ai 更新为 ai+ai/x。
如果变成的 ai==bi 的话,会得到ci个金币。1 ≤bi ≤10^3,0 ≤k ≤10^6
问,最多能够得到多少金币?

思路:

dp预处理出 1 变化为 x 的最小操作数,于是就转化为 n 个物品,每个物品有价值和花费,
求花费不超过k的最大总价值。但是二重循环会超时。
最后发现最小操作数最大不会超过12,所以花费不超过13*n,这样就能过了。

dp处理:
从小到大遍历每个数,用 当前数+因数 来更新后面较大的数的状态;

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m, k;
int a[N], cost[N];
int dp[1010][13010], w[N];

signed main(){
	Ios;
	for(int i=2;i<=1000;i++) cost[i]=1e9;
	
	for(int i=1;i<=1000;i++)
	{
		for(int j=1;j<=i;j++)
		{
			int t = i/j;
			cost[i+t] = min(cost[i+t], cost[i]+1);
		}
	}
	
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		m = min(m, 13*n);
		
		for(int i=1;i<=n;i++)
		{
			int x;cin>>x;
			a[i] = cost[x];
		}
		
		for(int i=1;i<=n;i++) cin>>w[i];
		
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<=m;j++) dp[i][j]=dp[i-1][j];
			for(int j=a[i];j<=m;j++)
			{
				dp[i][j] = max(dp[i-1][j], dp[i-1][j-a[i]]+w[i]);
			}
		}
		cout << dp[n][m] << endl;
	}
	
	return 0;
}

C. Weird Sum

题意:

求一个矩阵中,所有颜色相同的点的 哈密顿距离 之和。

思路:

哈密顿距离,可以分解成两个一维问题。
求所有相同种类点之间的距离之和,利用相邻两个点之间的小区间

Code:

const int N = 200010, mod = 1e9+7;
int T, n, m, k;
int a[N];
vector<int> v1[N], v2[N];

signed main(){
	Ios;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			int x;cin>>x;
			v1[x].pb(i), v2[x].pb(j);
		}
	
	int ans=0;
	for(int i=1;i<=100000;i++)
	{
		if(v1[i].size()==0) continue;
		int n = v1[i].size()-1;
		for(int j=0;j<n;j++)
		{
			ans += (v1[i][j+1]-v1[i][j])*((j+1)*(n-j));
		}
	}
	
	for(int i=1;i<=100000;i++)
	{
		sort(v2[i].begin(), v2[i].end());
		if(v2[i].size() == 0) continue;
		int n = v2[i].size()-1;
		for(int j=0;j<n;j++)
		{
			ans += (v2[i][j+1]-v2[i][j])*((j+1)*(n-j));
		}
	}
	cout << ans;
	
	return 0;
}

D. Integral Array

题意:

给定 n 个数,判断是否满足下列条件:
从中挑选出两个数 x≥y(可以相同),x/y 也在这 n 个数中。
n ≤10^6, maxa ≤10^6.

思路:

遍历每个数x,枚举其倍数y,判断是否是 [y, y+x-1] 这个区间中存在集合中的数(前缀和判断),并且y/x不存在。

Code:

const int N = 2000010, mod = 1e9+7;
int T, n, m, k;
int a[N], s[N], t[N];
set<int> st;
bool mp[N];

signed main(){
	Ios;
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		
		st.clear();
		
		for(int i=1;i<=n;i++){
			cin>>t[i];
			int x = t[i];
			a[x]++, mp[x]=1;
			st.insert(x);
		}
		for(int i=1;i<=m;i++) s[i] = s[i-1]+a[i];
		
		int flag=0;
		if(*st.begin() != 1) flag=1;
		
		for(auto x:st)
		{
			for(int j=x;j<=m;j+=x)
			{
				if(s[min(j+x-1, m)] - s[j-1] > 0 && !mp[j/x]) flag=1;
			}
		}
		
		for(int i=1;i<=m;i++) a[i] = mp[i] = 0;
		
		if(flag) cout<<"No\n";
		else cout<<"Yes\n";
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值