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;
}