atcoder353(A~G)

A:Buildings

题意:给出一组数列,设数列第一个值为X,求第一个大于X的下标,若不存在,输出-1

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N=105;
int a[N];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	int maxn=a[1],pos=-1;
	for(int i=2;i<=n;i++)
	{
		if(a[i]>maxn)
		{
			pos=i;
			break;
		}
	}
	cout<<pos<<endl;
	return 0;
}

B:AtCoder Amusement Park

题意:给出一个容量为x的容器和一组数列,数列内的每个值为一个整体,求最小要用几个容器才能全部装完

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N=105;
int a[N];
int main()
{
	int n,k,x;
	cin>>n>>k;
	queue<int>q;
	for(int i=1;i<=n;i++)
	{
		cin>>x;
		q.push(x);
	}
	int cnt=0;
	while(q.size())
	{
		int sum=0;
		while(sum+q.front()<=k&&q.size())
		{
			sum+=q.front();
			q.pop();
		}
		cnt++;
	}
	cout<<cnt<<endl;
	return 0;
}

C:Sigma Problem

题意:给出一个数组,设任意两个数所组成的不重复组合数的值为x,求所以x模10^8的值为多少

解题思路:若不考虑模的情况,可以从左到右遍历,每个值的贡献为n-i(i为当前值的下标),现在将模的问题考虑进来,两个组合数的最大值为2*10^8,模10^8就是减去一个10^8。

由此可得该题可以先算出总值,然后将数组从小到大排序,从右往左遍历,找出和超过10^8的1值并减去10^8

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const ll N=3e6,mod=1e8;
ll a[N];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	ll sum=0;
	for(int i=1;i<=n;i++)
	{
		sum+=a[i]*(n-1);
	}
	sort(a+1,a+n+1);
	int l=n;
	for(int i=1;i<=n;i++)
	{
		while(a[i]+a[l]>=mod&&l)l--;
		sum-=min(n-l,n-i)*mod;
		
	}
	cout<<sum<<endl;
	return 0;
}

D:Another Sigma Problem

题意:和c题一样,不过组合数的和变为字符串式的前后合并,最终所以组合数的值模998244353

解题思路:先考虑具体一个值(设为x)对整体的贡献,我们发现可以把整体分为x的前面和x的后面,x的前面对整体的贡献为x*(i-1),x的后面的值对于整体的贡献来说等于x乘以10^(具体值的长度)

防止超时,从右向左遍历,并用一个map来记录已经出现的长度的数量

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N=2e6,mod=998244353;
ll a[N];
int b[50];
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	memset(b,0,sizeof(b));
	ll sum=0;
	for(int i=n;i>=1;i--)
	{
		sum=(sum+a[i]*(i-1))%mod;
		ll tmp=0,cnt=10;
		for(int j=1;j<=20;j++)
		{
			tmp=(tmp+cnt*b[j])%mod;
			cnt*=10;
		}
		sum=(sum%mod+(a[i]*tmp)%mod)%mod;
		ll x=a[i];
		int y=0;
		while(x)
		{
			y++;
			x/=10;
		}
		b[y]++;
	}
	cout<<sum<<endl;
	return 0;
}

E:Yet Another Sigma Problem

题意:和C题一样,把数字改为字符串,把组合数的值改为,两个字符串的最长公共前缀的长度

解题思路:字典树的运用,根据题意可以构成一课字典树。在构建的同时记录出现的前缀的个数(n),每个前缀的贡献为C(2,n)=(n*(n-1)/2)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N=3e5+9;
ll tr[N][30],b[N];
ll id=0;
void insert(string s)
{
	int p=0;
	for(int i=0;i<s.size();i++)
	{
		int x=s[i]-'a';
		if(tr[p][x]==0)
		{
			tr[p][x]=++id;
		}
		p=tr[p][x];
		b[p]++;
	}
}
string s[N];
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
		insert(s[i]);
	}
	ll sum=0;
	for(int i=1;i<=id;i++)
	{
		sum+=b[i]*(b[i]-1)/2;
	}
	cout<<sum<<endl;
	return 0;
}

F:Tile Distance(大模拟)

G:Merchant Takahashi 

题意:一个人赶集,给出车费C,和m个集市,按顺序给出每个集市的位置t和利润p(下一个集市开始于上一个集市的结束),求可以获得的最大利润

解题思路:设f[i]为到达第i个集市的最大利润,由此可得f[i]=f[j]+abs(t[i]-t[j])*c+p(0<=j<i),直接枚举会超时,可以尝试将绝对值去掉:

当t[i]<=t[j]时,f[i]=f[j]-t[j]*c+t[i]*c+p

当t[i]>t[j]时,f[i]=f[j]+t[j]*c-t[i]*c+p

由此可得只需维护f[j]-t[j]*c和f[j]+t[j]*c即可,因为涉及到单点修改,区间查询,所以这里可以用线段树来维护。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
const int N=2e6;
const ll inf=1e18;
int n,m;
ll c;
class segt
{
	#define lson (rt<<1)
	#define rson (rt<<1|1)
	#define mid ((l+r)>>1)
	public:
	ll tr[N<<2];
	void pushup(int rt)
	{
		tr[rt]=max(tr[lson],tr[rson]);
	}
	void build(int rt,int l,int r,vector<ll>&v)
	{
		if(l==r)
		{
			tr[rt]=v[l-1];
			return;
		}
		build(lson,l,mid,v);
		build(rson,mid+1,r,v);
		pushup(rt);
	}
	void update(int rt,int l,int r,int idx,ll v)
	{
		if(l==r)
		{
			tr[rt]=max(tr[rt],v);
			return;
		}
		if(idx<=mid)
		{
			update(lson,l,mid,idx,v);
		}
		else
		{
			update(rson,mid+1,r,idx,v);
		}
		pushup(rt);
	}
	ll querry(int rt,int l,int r,int x,int y)
	{
		if(x<=l&&r<=y)
		{
			return tr[rt];
		}
		ll res=-inf;
		if(x<=mid)
		{
			res=max(res,querry(lson,l,mid,x,y));
		}
		if(y>mid)
		{
			res=max(res,querry(rson,mid+1,r,x,y));
		}
		return res;
	}
}lsg,rsg;
int main()
{
	cin>>n>>c;
	vector<ll>v(n);
	for(int i=0;i<n;i++)
	{
		v[i]=-inf;
	}
	v[0]=0;
	lsg.build(1,1,n,v);
	rsg.build(1,1,n,v);
	ll ans=0;
	cin>>m;
	for(int i=0;i<m;i++)
	{
		int t;
		ll p;
		cin>>t>>p;
		int id=t;
		t--;
		ll dp1=lsg.querry(1,1,n,1,id)-1ll*c*t;
		ll dp2=rsg.querry(1,1,n,id,n)+1ll*c*t;
		ll dp=max(dp1,dp2)+p;
		ans=max(ans,dp);
		lsg.update(1,1,n,id,dp+1ll*c*t);
		rsg.update(1,1,n,id,dp-1ll*c*t); 
	}
	cout<<ans<<endl;
	return 0;
}

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值