Codeforces #694 Div2部分题解(除了E题)

A. Strange Partition
大致题意:给定一个x和一串数组,可以让数组的任意两相邻元素合并,求数组所有数向下取整之和的最大值和最小值
解题思路:对于所有数,其向下取整都会得到小于或等于该数的结果,故当不进行任何合并的时候和最小,同理,当所有加起来再向下取整的结果是最大
时间复杂度O(N)
代码:


#include<iostream>
using namespace std;
typedef long long LL;
int main()
{
   int t;
   cin>>t;
   while(t--)
   {
   	int n,x;
   	cin>>n>>x;
   	LL max_n=0;
   	LL sum=0;
   	LL min_n=0;
   	while(n--)
   	{
   		LL a;
   		 cin>>a;
   		if(a%x) max_n=max_n+a/x+1;
   		else max_n=max_n+a/x;
   		
   		sum+=a;
   	}
   	if(sum%x) min_n=sum/x+1;
   	else min_n=sum/x;
   	cout<<min_n<<" "<<max_n<<endl;
   }
}

B. Strange List
大致题意:给定一个数组和一个数q,从头到尾遍历,如果q能整除当前数,就在当前数组后面添加q个整除的结果,否则就直接停止,最终输出数组所有元素之和
解题思路:考虑到给的数据太大,无法直接模拟,但通过数学演算可以发现,每次增加的q个数之和刚好就是当前元素,而且可以观察出来对于被增加的q个数,这些数在下次操作后产生的q* q个数之和恰好也是当前元素,故可以发现整个结果具有一定的周期性,当其恰好无法整除的时候便停止,这里只需要先预处理出来当前数组里关于q的次幂的最小值,同时记录满足该次幂最小值的最小下标,然后用所有数的和乘最小次幂再加上前几个数的和
时间复杂度是O(n*logn)
代码:

#include<iostream>
#include<cstring>
using namespace std;
const int N=2e5+10;
int a[N];
int cnt[N];	
int main()
{
  int t;
  cin>>t;
  while(t--)
 {
  	int n,x;
  	cin>>n>>x;
  	long long sum=0;
  	for(int i=0;i<n;i++) 
      {
       cin>>a[i];
       sum+=a[i];
      }
      int min_i=0x3f3f3f3f,min_c=0x3f3f3f3f;
   for(int i=n-1;i>=0;i--)
   {
   	int c=0;
   	int k=x;
   	while(!(a[i]%k))
   	{
   		k*=x;
   		c++;
   	}
   	if(c<=min_c)
   	{
   		min_c=c;
   		min_i=i;
   	}
   }
   long long qzh=0;
   for(int i=0;i<min_i;i++)
     qzh+=a[i];
   sum=(min_c+1)*sum+qzh;
   cout<<sum<<endl;
   
 }
} 

C. Strange Birthday Party
大致题意:有n个人,m份礼物,其中每个人都有一个下标k,对于m份礼物,其价格单调上升,现在要给这些人都买礼物,但需要满足买的礼物的下标要小于等于k,或者直接给它们与第k个下标的礼物相同价值的钱,每个礼物只能购买一次,求最少花费
思路:对于所有人来说,能优先购买礼品肯定是最省钱的,但对于下标比较大的人,它往往需要更多钱,而且对于这些人来说如果直接给钱的话那么肯定是最贵的,故可以先对下标排序,对于k最大的人直接买礼物,而且可以发现礼物肯定是优先买最便宜的再买最贵的,故只需要用一个指针指向当前的礼物,然后向后遍历即可,当礼物下标与当前从后遍历的人的下标k相同时,对于后面的人只需要给相应的钱即可
时间复杂度O(Nlogn)
代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=3e5+10;
int a[N],c[N];
int main()
{
   int t;
   cin>>t;
   while(t--)
  {
   	int n,m;
   	cin>>n>>m;
   	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
   	for(int i=1;i<=m;i++) scanf("%d",&c[i]);
   	sort(a+1,a+n+1);
   	long long sum=0;
   	for(int i=n,j=1;i>=1;i--)
   	{
   		if(a[i]>=j&&j<=m) sum+=c[j++];
   		else
   		{
   			sum+=c[a[i]];
		}
    }
    cout<<sum<<endl;
  }
} 

D. Strange Definition
大致题意:给定一个数组,给定一个定义:相邻:满足两个数的最小公倍数除以它们的最大公约数是一个数的完全平方数的两个数称它们相邻。每个数与自己肯定是相邻的,经过一秒之后会发生一定的变化,所有相邻的数都会变成这几个相邻数的积,比如20,5,80在经过一秒后都变成8000,求经过k秒后最大的相邻的数有多少?

思路:gcd(x,y)=xy/lcm(x,y),那么gcd(x,y)/lcm(x,y)=xy/lcm²(x,y)
要想让它们相除是完全平方数,即x * y是完全平方数
根据算数基本定理,任何一个数都可以表示成多个质数的指数的乘积
那么两个数相邻的充要条件其实就是看它们在分解了所有偶数次质因子之后的结果是否相同,若相同则相邻
故只需要对当前所有数分解偶数次的质因子,然后统计当前结果出现的次数,出现次数最多即相邻的最大,这里是对于第0秒的情况
但当经过k秒之后会有一定的变化,考虑到题目给的k秒过大,故可以考虑是否存在一种性质使得经过k秒之后结果不变,通过分析可以发现,如果某个数出现了奇数次,那么它的次数不变,如果出现偶数次,那么它经过变换之后筛掉偶次质因子后结果为1,如果之前是1则不变。证明,如果有偶数个相等的数假设为p1 * p2,p3 * p4,经过一秒之后它们都会变成p1 * p2 p3 * p4,此时可以表示成(p1 p2)^2,再经过筛偶次质因子之后就变成了1,如果是奇数个相同的假设为p1 * p2,p3 * p4,p5 * p6,那么经过一秒之后就会变成(p1 * p2)(p3 p4 )* (p5 * p6),即为(p1 * p2)^3,不会被筛,故次数不变,如果只有一个的话它仍然不变,而且可以发现,经过一秒之后其实所有结果就将不再变化
时间复杂度(N*Log x)
代码:

#include<iostream>
#include<map>
using namespace std;
map<int,int> m;
int main()
{
   int t;
   cin>>t;
   while(t--)
   {
   	m.clear();
   	int n;
   	scanf("%d",&n);
   	for(int i=0;i<n;i++)
   	{
   		int a;
   		scanf("%d",&a);
   		int x=a;
   		for(int j=2;j<=x/j;j++)
   		 while(x%(j*j)==0)
   		 {
   		 	x=x/j/j;
   		 }
   		 m[x]++;
   	}
   	int res1=0;
   	int oddnum=0;
   	int res2=0;
   	    for(auto t:m)
   	    {
   	    	res1=max(res1,t.second);
   	    	if(t.second&1)
   	    	{
   	    		oddnum=max(oddnum,t.second);		    		
   			}
   			else res2+=t.second;
   		}
   		if(m[1]&1) res2+=m[1];
   		res2=max(res2,oddnum);
   		 long long q;
   		 scanf("%lld",&q);
   		 while(q--)
   		 {
   		 	long long w;
   		 	scanf("%lld",&w);
   		 	if(!w)
   		 	{
   		 		printf("%d\n",res1);
   			}
   			else{
   				printf("%d\n",res2);
   			}
   		} 
   	}
   
}

F. Strange Housing
大致题意:给定一个无向图,要求在图中某些点放置老师,要求满足:
1.老师与老师之间不能通过道路相连
2.整个图是连通的
3.学生若相连那么它们的道路将没有作用
解题思路:题意就是染色之后必须让图连通,已知学生相邻会让道路减少,故尽量不让学生连通,这里的做法是对于所有点,如果相邻的点没有老师,那么就在该点为老师,如果有了就让该点为学生
代码:

#include<iostream>
#include<cstdio>
using namespace std;
#include<cstring>
const int N=3e5+10;
int h[N],e[N*2],ne[N*2],idx;
int res;
int n,m;
int te[N],idx2;
bool st[N];
bool col[N];
void add(int x,int y)
{
	e[idx]=y;
	ne[idx]=h[x];
	h[x]=idx++;
}
void dfs(int u,int pa)
{
	if(res==n) return ;
	
	st[u]=true;
	res++;
	bool flag=false;
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i];
	    if(st[j]&&col[j]) {
	    	flag=true;
	    	break;
	  }
    }
	if(!flag) 
	{
		col[u]=true;
		te[idx2++]=u;
	}
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i];
	    if(j==pa) continue;
	    if(st[j]) continue;
	    
	    	dfs(j,u);
		
	}
	
}
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		
		
		res=0;
		idx=0;
		idx2=0;
		scanf("%d%d",&n,&m);
		
		for(int i=0;i<=n;i++) 
		{col[i]=false,st[i]=false;
		h[i]=-1; 
		} 
		while(m--)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			add(x,y);
			add(y,x);
		}
		dfs(1,-1);
		if(res==n) 
		{
		puts("YES");
		 printf("%d\n",idx2);
		 for(int i=0;i<idx2;i++)
		  printf("%d ",te[i]);
		  puts("");
	    }
	    else puts("NO");
		
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值