Codeforces Round 925 (Div. 3)

D. Divisible Pairs

题意:给定一个长度为n(2<=n<=2*10^5)的数组,给出两个数x、y(1<x,y<=10^9),找出完美对的个数

完美对满足 (ai+aj)整除x  (ai-aj)整除y 且(1<=i<j<=n)

统计数组a中的完美对有多少个

思路:统计<i,j>的对数

         一般来说 就是枚举 i,j  时间复杂度:n*(n-1)/2--->O(n^2)--->会超时

          这时就想优化  枚举i 将j进行分类 按照分类,提前统计-->避免查询的时候重复统计

          根据题意可得(ai+aj)%x==0 (ai-aj)%y==0

          aj=-ai%x aj=ai%y -->满足这两个条件 就可与i组成完美对 就提前统计

          结合map用pair去存储个数  

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=5e5+10;
map<PII,int>mp;
int a[N];
int main()
{
	int t;cin>>t;
	while(t--)
	{
	    int n;cin>>n;
	    ll x,y;cin>>x>>y;
	    for(int i=1;i<=n;i++)
	    {
	    	cin>>a[i];
	    	mp[{a[i]%x,a[i]%y}]++;//满足条件的个数有多少个
		}
		ll ans=0;
		for(int i=1;i<=n;i++)
		{
			mp[{a[i]%x,a[i]%y}]--;//先减去自身的 然后统计后面满足这个条件的个数
			ans+=mp[{(x-a[i]%x)%x,a[i]%y}];//(x-a[i]%x)%x-->-a[i]%x-->得到正数
		}
		cout<<ans<<endl;
	}
	return 0;
}

 E. Anna and the Valentine's Day Gift(贪心)

    题意:

输入数据 

9

2 2

14 2

3 5

9 56 1

4 10

1 2007 800 1580

4 5

5000 123 30 4

10 10

6 4 6 2 3 1 10 9 10 7

1 1

6

1 1

10

8 9

1 2 9 10 10 2 10 2

4 5

10 10 10 10

 输出数据

Sasha
Anna
Anna
Sasha
Sasha
Anna
Anna
Anna
Sasha

思路:题意中若最后的数 大于等于10^m则Sasha赢 否则Anna赢

实际上就是求最终的长度与之相比 10^2=100 故 求的就是最终的数的长度与m+1的长度的大小

 Anna的操作 XXZZ--ZZXX   XZ00-ZX Anna可以使有后缀0的数 长度变短 故其每一次进行操作 都应该找后缀0 最长的进行翻转

Sasha  若选择的两个数为 xxz yyo -->xxzyyo  xxz000  yyot-->xxz000yyot 这样可以保护后缀0 

故Anna 应可能使有后缀0 翻转 使长度减小 Sasha 应尽可能的使有后缀0 与其他数结合 使其长度不变 (采用贪心的策略 用后缀0 的长度从大到小排序 每次处理后缀0 长度最大的--即最优) 

#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=5e5+10;
map<PII,int>mp;
int a[N];
int main()
{
	int t;cin>>t;//t  t (1≤t≤10^4)
	while(t--)
	{
	    int n,m;cin>>n>>m;//n, m(1≤n≤2*10^5, 0≤m≤2*10^6) 
	    priority_queue<PII>q;//采用优先队列 对后缀0进行从大到小的排序(优先队列默认从大到小排)
	    for(int i=1;i<=n;i++)
	    {
	    	cin>>a[i];
	    	//to_string 是C++11新引进的函数,用于将各种类型(包括整型、浮点型、布尔型等)转换为字符串类型。
	    	int len1=to_string(a[i]).length();//统计每个数的总长度
	    	int len2=0;//统计后缀0的长度
	    	while(a[i]%10==0)
	    	{
	    		len2++;
	    		a[i]/=10;
			}
			q.push({len2,len1});
		}
		int x=0;
		int flag=0;
		while(q.size())
		{
			PII t=q.top();
			q.pop();
			if(!flag)
			{
				x+=t.second-t.first;//Anna 删掉后缀0
			}
			else
			{
				x+=t.second;//Sasha 保护后缀0
			}
			if(!flag) flag=1;
			else flag=0;
		}
		if(x>=m+1) cout<<"Sasha"<<endl;
		else cout<<"Anna"<<endl;
	}
	return 0;
}

F. Chat Screenshots(拓扑排序)

题意:

 输入样例:

10

5 1

1 2 3 4 5

4 4

1 2 3 4

2 3 1 4

3 2 1 4

4 2 3 1

6 2

1 3 5 2 4 6

6 3 5 2 1 4

3 3

1 2 3

2 3 1

3 2 1

10 2

1 2 3 4 5 6 7 8 9 10

10 9 8 7 6 5 4 3 2 1

1 1

1

5 2

1 2 3 5 4

2 1 3 5 4

3 3

3 1 2

2 3 1

1 3 2

5 4

3 5 1 4 2

2 5 1 4 3

1 5 4 3 2

5 1 4 3 2

3 3

1 3 2

2 1 3

3 2 1 

 输出样例:

YES
YES
YES
YES
NO
YES
YES
YES
YES
NO

思路:根据 题意 求得就是能否找出一种排队方式,满足k个人提高的关系

本体考察了拓扑排序 难点在于如何抽象出来

例如 

5 4

3 5 1 4 2  --->  5>1>4>2

2 5 1 4 3  --->5>1>4>3

1 5 4 3 2 --->5>4>3>2

5 1 4 3 2 --->1>4>3>2

如何代替这种大小关系 考虑用图 用有向边去表示

2<4 则表示有一条边 由2指向4 依次取建图

根据拓扑排序 能表示出来 2 3 4 1 5 若是有环则不能 

#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
vector<int>v[N];
set<int>s[N];
int a[N],d[N];
int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n,k;cin>>n>>k;
		for(int i=1;i<=n;i++) d[i]=0,s[i].clear();
		for(int i=1;i<=k;i++)
		{
		    for(int j=1;j<=n;j++) cin>>a[j];
		    //有重边 用set进行优化 不能直接在这里进行 入度的计算 有重边 会导致出错
		    //建边
		    for(int j=2;j<n;j++) s[a[j]].insert(a[j+1]);
		}
	    for(int i=1;i<=n;i++)
	    {
	    	for(auto it:s[i])
	    	{
	    		d[it]++;
			}
		}
		//拓扑排序--看是否有环 若有环则不行 
	    queue<int>q;
		for(int i=1;i<=n;i++) if(!d[i]) q.push(i);
	    int ans=0;
	    while(q.size())
	    {
	    	int t=q.front();q.pop();
	    	ans++;
	    	for(auto it:s[t])
	    	{
	    		d[it]--;
	    		if(!d[it]) q.push(it);
			}
		}
		if(ans==n) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值