Codeforces Round 695 Div2


A. Wizard of Orz

传送门
题意:n个整数,开始全是0,每一秒全部+1模10,可以在任意的位置,让序列暂停。它的相邻位过1秒钟暂停,相隔为2的位置过2秒钟暂停,问操作后得到的最大的数是多少?
思路:最大第一位必须是9,所以第二位是8,第二位暂停后第一位和第三位都是9,剩下n-3个数从0开始加并模10。

AC代码:

#include<bits/stdc++.h>
using namespace std;

int n,m;
void solve()
{
	cin>>n;
	if(n==1) cout<<9<<endl;
	else if(n==2) cout<<98<<endl;
	else if(n==3) cout<<989<<endl;
	else
	{
	    cout<<989;
	    for(int i=1;i<=n-3;i++)
	        cout<<(i-1)%10;
	   	cout<<endl;
	}
}
 
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

B. Hills And Valleys

传送门

题意:长度为n的序列,如果 a [ i ] > a [ i + 1 ] & & a [ i ] > a [ i − 1 ] a[i]>a[i+1]\&\& a[i]>a[i-1] a[i]>a[i+1]&&a[i]>a[i1]为波峰,如果 a [ i ] < a [ i + 1 ] & & a [ i ] < a [ i − 1 ] a[i]<a[i+1]\&\& a[i]<a[i-1] a[i]<a[i+1]&&a[i]<a[i1]为波谷,可以把一个数变成任意值,问操作后波峰波谷最小值为多少?

思路:分析得出,要改变 a [ i ] a[i] a[i]减少波峰波谷,就改成 a [ i − 1 ] a[i-1] a[i1]或者 a [ i + 1 ] a[i+1] a[i+1],但可能产生新的波峰波谷,所以我们枚举每一个波峰波谷的两周情况,取减少的最大值,用原来波峰波谷的和减去最大值。

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (int i=(a);i<=(b);i++)
#define per(i,a,b) for (int i=(a);i>=(b);i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define fi first
#define se second
#define sz(x) ((int)(x).size())
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
const int N=3e5+10;
int n;
int a[N];
 
bool check(int x)
{
	if(x<=1||x>=n) return 0;
	if(a[x]>a[x-1]&&a[x]>a[x+1]) return 1;
	if(a[x]<a[x-1]&&a[x]<a[x+1]) return 1;
	return 0;
}
 
void solve()
{
	cin>>n;
	int sum=0;
	rep(i,1,n) cin>>a[i];
	rep(i,1,n) sum+=check(i);
		
	int maxv=0;
	rep(i,2,n-1)
	{
		int k=check(i-1)+check(i)+check(i+1);
		int tmp=a[i];
		a[i]=a[i-1];
		int p=check(i-1)+check(i)+check(i+1);
		maxv=max(maxv,k-p);
		a[i]=a[i+1];
		p=check(i-1)+check(i)+check(i+1);
		maxv=max(maxv,k-p);
		a[i]=tmp;
	}
 
	cout<<sum-maxv<<endl;
}
 
int main()
{
	ios::sync_with_stdio(0); cin.tie(0);
	int t;
	cin>>t;
	while(t--) solve();
	return 0;
}

C. Three Bags

传送门

题意:你有三个背包,可以每一次从两个非空背包中取出两个数。比如你从第一个背包中取出了 a a a,第二个背包中取出了 b b b,之后第一个背包中的 a a a变成 a − b a-b ab,第二个背包中的 b b b就没有了。多次操作,最后一个背包有一个数,其余两个背包是空的,问此时剩余的最大值是多少?

思路:枚举最后剩下的数字在哪一个袋子里,这里以在 A A A为例,操作一次,把 a a a换成 a − b a-b ab,消除 b b b,原价值为 a + b a+b a+b,操作完变成 a − b a-b ab可以理解为改变b的正负号,对一个数进行奇数次操作是负收益,偶数次是正收益, A A A中有 n 1 n_1 n1个元素, n 1 − 1 n_1-1 n11个元素作为 b b b转移出去再转移回来,负负得正,所以 A A A中所有数都是正收益。

考虑 B , C B,C B,C袋子最优解

1. B , C B,C B,C分别剩下一个,然后分别作为 b b b A A A
除了 B B B剩下的那个数,其他数字先给 C C C,再由 C C C A A A,偶数次是正收益, C C C同理,只有最后留下来的那个数是负收益,要是总价值最大,就使 B , C B,C B,C剩下的两个数最小。

2. 最后 B B B剩下一个数,然后作为 b b b A A A
那么 B B B中其他 n 2 − 1 n_2-1 n21个数先转移到 C C C,再转移回 B B B,再一起转移回 A , B A,B A,B中所有元素都是奇数次操作,都是负收益, C C C中收益都是正收益。

(如果 B B B中其余 n 2 − 1 n_2-1 n21个元素先转移到 C C C,然后 C C C全部转移给 A A A会不会更优呢?)
如果这样 B B B中剩下的数是正收益, n 2 − 1 n_2-1 n21个数是正收益, C C C全部都是负收益,然而1的情况一定比这样更优,所以一定不是最优解。

3. 最后 C C C剩下一个数,然后作为 b b b A A A
2同理, C C C中收益都是负收益, B B B都是正收益

A , B , C A,B,C A,B,C等价枚举上述情况

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
 
const int N=3e5+10;
 
int n1,n2,n3;
ll a[N],b[N],c[N];
 
void solve()
{
	cin>>n1>>n2>>n3;
	ll suma=0,sumb=0,sumc=0;
	rep(i,1,n1)
	{
		cin>>a[i];
		suma+=a[i];
	}
	rep(i,1,n2) 
	{
		cin>>b[i];
		sumb+=b[i];
	}
	rep(i,1,n3) 
	{
		cin>>c[i];
		sumc+=c[i];
	}
	ll sum=suma+sumb+sumc;
 
	sort(a+1,a+1+n1);
	sort(b+1,b+1+n2);
	sort(c+1,c+1+n3);
 
	ll ans=0;
	ans=max(ans,sum-2*(b[1]+c[1]));
	ans=max(ans,sum-2*(a[1]+c[1]));
	ans=max(ans,sum-2*(a[1]+b[1]));
 
	ans=max(ans,suma+sumb-sumc);
	ans=max(ans,suma+sumc-sumb);
	ans=max(ans,sumb+sumc-suma);
 
	cout<<ans<<endl;
}	
 
int main()
{
	ios::sync_with_stdio(false); cin.tie(0);
	solve();
	return 0;
}

D. Sum of Paths

传送门

题意:有个机器人在 [ 1 , n ] [1,n] [1,n]的直线上面从任意起点走 k k k步,格子权值会改变,求每次改变后路径的权值和?

思路: d p dp dp,我们要求所有路线下每个格子经过的次数即 c n t [ i ] cnt[i] cnt[i]

f [ i ] [ j ] f[i][j] f[i][j]表示走了 j j j步最终停到 i i i的所有方案数,也等价于从从 i i i走了 j j j步到达的点方案数,所以经过 i i i点的所有路径就是表示走了 j ( j < = k ) j(j<=k) j(j<=k)步到达 i i i,再从 i i i点走 k − j k-j kj步的所有路径。

所以每个点所有路线经过的次数 c n t [ i ] + = f [ i ] [ j ] ∗ f [ i ] [ k − j ] cnt[i]+=f[i][j]*f[i][k-j] cnt[i]+=f[i][j]f[i][kj],每次修改只要改变 a [ i ] a[i] a[i],就可求出 s u m = ∑ i = 1 n c n t [ i ] ∗ a [ i ] sum=\sum_{i=1}^{n}{cnt[i]*a[i]} sum=i=1ncnt[i]a[i]

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned long long ull;
 
const int N=5010;
const int mod=1e9+7;
 
int n,k,q;
ll a[N],cnt[N];
ll f[N][N]; // f[i][j]表示走了j步最终停到i的所有方案数
ll sum;
 
 
int main()
{
	ios::sync_with_stdio(false); cin.tie(nullptr);
	
	cin>>n>>k>>q;
	rep(i,1,n)
	{
		cin>>a[i];
		f[i][0]=1; //走0步到i就是i这个点,为1种情况
	}
 
	rep(j,1,k)
		rep(i,1,n)
		{
			if(i==1) f[i][j]=f[i+1][j-1]%mod;
			else if(i==n) f[i][j]=f[i-1][j-1]%mod;
			else f[i][j]=(f[i-1][j-1]+f[i+1][j-1])%mod;
		}
 
	rep(i,1,n)
		rep(j,0,k)
			cnt[i]=(cnt[i]+f[i][j]*f[i][k-j])%mod;
 
	rep(i,1,n) sum=(sum+cnt[i]*a[i]%mod)%mod;
 
	while(q--)
	{
		int i,x;
		cin>>i>>x;
		sum=(sum-a[i]*cnt[i]%mod+mod)%mod;
		a[i]=x;
		sum=(sum+x*cnt[i]%mod+mod)%mod;
		cout<<sum<<endl;
	}
	return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值