Codeforces Round #536 (Div. 2)题解

Codeforces Round #536 (Div. 2)题解

http://codeforces.com/contest/1106

A. Lunar New Year and Cross Counting

解题思路

暴力对全图进行以此搜索即可

AC代码

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char m[505][505];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%s",m[i]+1);
	int cnt=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(m[i][j]=='X'&&m[i-1][j-1]=='X'&&m[i+1][j+1]=='X'&&m[i-1][j+1]=='X'&&m[i+1][j-1]=='X')
			{
				cnt++; 
			}
		}
	}
	cout<<cnt<<endl;
}

B. Lunar New Year and Food Ordering

题目大意

简单模拟.有n个顾客,m种菜,每种菜有一定的价值和数量,顾客优先渴望一种菜品,如果缺乏这种菜品则会在现有的菜品中选择最便宜(如果有多个价格一样为最便宜的菜品,则选择尽可能便宜的)的给顾客,如果顾客不能吃够需求数量的菜就不会给钱,不论如何都会尽量给一个顾客菜吃,问最终获得的钱数

解题思路

依照题意模拟就行了模拟

AC代码

#include<iostream>
#include<queue>
#include<algorithm>
#define int long long
using namespace std;
struct node{
	int c,id;
	friend bool operator<(node x,node y)
	{
		if(x.c==y.c) return x.id<y.id;
		else return x.c<y.c;
	}
}C[100005];
int a[100005];
int cs[100005];
int32_t main()
{
	int n,m;
	long long tot=0;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]),tot+=a[i];
	for(int i=1;i<=n;i++) scanf("%lld",&C[i].c),C[i].id=i,cs[i]=C[i].c;
	sort(C+1,C+1+n);
	int t,d;
	int loc=1;
	while(m--)
	{
		scanf("%lld%lld",&t,&d);
		if(a[t]>=d)
		{cout<<d*cs[t]<<endl;a[t]-=d;continue;}
		else
		{
			int ans=0;
			d-=a[t];
			ans+=a[t]*cs[t];
			a[t]=0;
			while(d&&loc<=n)
			{
				if(d>a[C[loc].id])
				{
					d-=a[C[loc].id];
					ans+=a[C[loc].id]*C[loc].c;
					a[C[loc].id]=0;
					loc++;
				}
				else
				{
					a[C[loc].id]-=d;
					ans+=d*C[loc].c;
					d=0;
				}
			}
			if(d!=0) ans=0;
			cout<<ans<<endl;
		}
	}
}

C. Lunar New Year and Number Division

题目大意

给出一些数,使其分为若干集合(每个集合最少两个数),要求集合中数和的平方的和最小

解题思路

集合自然是越小越好,因此尽量为2元集合,再者小大搭配

AC代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long 
int arr[300005];
int32_t main()
{
	int n;
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&arr[i]);
	}
	sort(arr+1,arr+1+n);
	int sum=0;
	for(int i=1;i<=n/2;i++)
	{
		sum+=(arr[i]+arr[n-i+1])*(arr[i]+arr[n-i+1]);
	}
	cout<<sum<<endl;
}

D. Lunar New Year and a Wander

题目大意

给出一幅连通图,对图进行遍历,已经走过的点可以重复走,问第一次走过点的字典序最小的点序列

解题思路

优先队列存入队的点优先搜索序号小的点.

AC代码

#include<cstdio>
#include<vector>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
vector<int> g[100005];
vector<int> ans;
bool vis[100005];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	memset(vis,0,sizeof(vis));
	while(m--)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	priority_queue<int, vector<int>, greater<int> > q;
	q.push(1);
	vis[1]=1;
	while(!q.empty())
	{
		int x=q.top();
		q.pop();
		ans.push_back(x);
		for(auto v:g[x])
		{
			if(!vis[v])
			{
				vis[v]=1;
				q.push(v);
			}
		}
	}
	for(int i=0;i<ans.size();i++)
	{
		cout<<ans[i];
		if(i==ans.size()-1) cout<<endl;
		else cout<<' ';
	}
}

E. Lunar New Year and Red Envelopes

题目大意

现在有一些红包其在s,t天之间可以被收取,若要收取这个红包则需要从开始收取的那一天一直到第d天才可以收下这个红包,收取后可以得到利益w.A按照一定的贪心策略收取红包:在一天中尽可能选择金额大的红包,如金额相同则选择d尽可能大的红包.现有一人可以有m天的机会来阻止A收取红包,即他可以选择m天使得这m天中A不能开始收取红包,问能使A收到最少金额红包的金额是多少

解题思路

对天数倒着DP,同时对天数和阻止次数DP即可

AC代码

#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
#include<vector>
#define int long long
using namespace std;
typedef pair<int,int> pii;
const int size=1e5+5;
vector<pii> days[size];
vector<pii> dayt[size];
multiset<pii> ms;
int dp[size][205];
int32_t main()
{
 	int n,m,k;
 	scanf("%lld%lld%lld",&n,&m,&k);
 	int s,t,d,w;
 	for(int i=1;i<=k;i++)
 	{
 		scanf("%lld%lld%lld%lld",&s,&t,&d,&w);
 		days[s].push_back(pii(-w,-d));
 		dayt[t].push_back(pii(-w,-d));
 	}
 	for(int i=n;i>=1;i--)
 	{
 		for(auto t:dayt[i]) ms.insert(t);
 		for(int j=0;j<=m;j++)
		{
		 	if(!ms.empty()) dp[i][j]=dp[-(*ms.begin()).second+1][j]-((*ms.begin()).first);
		 	else dp[i][j]=dp[i+1][j];
		 	if(j) dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
		 }
		 for(auto s:days[i]) ms.erase(ms.find(s));
	}
	cout<<dp[1][m]<<endl;
}

F. Lunar New Year and a Recursive Sequence

题目大意

给出一个序列,其前k-1项为1,其中对 i &gt; k i&gt;k i>k的项可以通过公式
f i = ( ∏ j = 1 k f i − j b j ) m o d   p f_i=(\prod_{j=1}^{k}f^{b^j}_{i-j})mod\ p fi=(j=1kfijbj)mod p
得出,现给出序列的第n项为m问第k项是否存在,若存在为几

解题思路

设第k项为x则原式可以化为求解 x q % p = m x^q\%p=m xq%p=m其中q可以通过矩阵快速幂得到.这时为了求解x我们需要用到原根的性质.当a为p的原根时函数 G ( b ) = a b m o d   p G(b)=a^b mod\ p G(b)=abmod p有循环节 ϕ ( p ) \phi(p) ϕ(p)其中且循环节中的数都是不相同的因此总是有唯一对应的故要求解x仅需要求解p的原根的几次方求模为m再对这个原根乘方即为答案.其中998244353有大家都直到的原根"3"(反正我原来不知道)由此通过上述方法求解即可

AC代码

#include<bits/stdc++.h> 
#define int long long
using namespace std;
typedef long long LL;
unordered_map<LL,LL> mp;
const int mod=998244353;
struct mat{
	LL m[110][110];
	mat(int x=0){memset(m,0,sizeof m);for(int i=1;i<110;i++)m[i][i]=x;}
	friend mat operator*(mat a,mat b){
		mat nxt;
		for(int i=1;i<110;i++)for(int j=1;j<110;j++)for(int k=1;k<110;k++)
			nxt.m[i][j]=(nxt.m[i][j]+a.m[i][k]*b.m[k][j])%(mod-1);
		return nxt;
	}
};

mat quick_pow_m(mat x,int b)
{
	mat ans(1);
	while(b)
	{
		if(b&1) ans=ans*x;
		x=x*x;
		b>>=1;
	}
	return ans;
}
int quick_pow(int a,int b,int p)
{
	int ans=1;a%=p;
	while(b)
	{
		if(b&1) ans=ans*a%p;
		a=a*a%p;
		b>>=1;
	}
	return ans;
}
int BSGS(int B,int N,int P=mod)
{
	mp.clear();
	if(B%P==0) return -1;
	LL ans=0;
	LL m=ceil(sqrt(P));
	for(int i=0;i<=m;i++)
	{
		if(!i) ans=N%P,mp[ans]=i;
		else
		{
			ans=ans*B%P;
			mp[ans]=i;
		}
	}
	LL t=quick_pow(B,m,P);ans=1;
	for(int i=1;i<=m;i++)
	{
		ans=(ans*t)%P;
		if(mp[ans])
		{
			int s=i*m-mp[ans];
			return (s%P+P)%P;
		}
	}
	return -1;
}
int exgcd(int a,int b,int &x,int &y)
{
	if(b==0)
	{
		y=0;
		x=1;
		return a;
	}
	int r=exgcd(b,a%b,x,y);
	int temp=y;
	y=x-(a/b)*y;
	x=temp;
	return r;
}
int32_t main()
{
	int k;
	mat s(0);
	scanf("%lld",&k);
	for(int i=1;i<k;i++) s.m[i][i+1]=1;
	for(int i=1;i<=k;i++)	scanf("%lld",&s.m[k][k+1-i]);
	int n,fn;
	scanf("%lld%lld",&n,&fn);
	int temp=quick_pow_m(s,n-k).m[k][k];
	int ans=BSGS(3,fn);
	if(ans==-1) {cout<<-1<<endl;return 0;}
	int x,y;
	LL g=exgcd(temp,mod-1,x,y);
	if(ans%g) {cout<<-1<<endl;return 0;}
	int p=(ans/g*x%(mod-1)+mod-1)%(mod-1);
	ans=quick_pow(3,p,mod);
	cout<<ans<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值