〖补〗: Gym 102411 / ICPC 2019 North-Western Russia
M - Managing Difficulties Gym - 102411M
题意:
求满足 a[j]−a[i]=a[k]−a[j]的i,j,k有几组。
思路:
a[j]−a[i]=a[k]−a[j]
可化为: 2×a[j]-a[k])=a]i]
- 枚举i时:
-
- 把i的放到map里
- 在枚举j,k的时
-
- 利用2×a[j]-a[k])=a]i]和
-
- map自带的"二分查询":mp.count()匹配
-
- 来把枚举i的时间复杂度O(n)降低到O(logn)。
unordered_map<>等价于无序(不排序)的map容器
代码:
- 来把枚举i的时间复杂度O(n)降低到O(logn)。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
int t;
cin>>t;
while(t--)
{
unordered_map<int,int> graph;
int ans=0;
int n;
cin>>n;
int a[n+1];
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
graph[ a[i] ]++;
for(int k=i+2;k<=n;k++)
{
int j=i+1;
/*因为graph里面含有所有小于等于当前i的a[]数组的数据
*所有:只要j=i+1,就可以(假)遍历所有小于j的数组
*/
if( graph.count(2*a[j]-a[k]) )
ans+=graph[ 2*a[j]-a[k] ];
}
}
cout<<ans<<endl;
}
return 0;
}
J - Just the Last Digit Gym - 102411J
题意:
要求:有一张有向图, 只能从小的点跑向大的点,
input:点a跑到点b的可行方案数的个位数(a<b)
output:让任意两点间是否能直达.
思路:
点a到点b的方法只有:直达或者间接到达 (废话)
故方法:
- 枚举求出:所有间接可达的方案总数(具体看代码)
- %10后如果与给出的个位数相同, 则无法直达, 反之可以直达.
代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 510;
char mp[MAXN][MAXN];
int res[MAXN][MAXN];
int main(void)
{
int n; cin >> n;
for (int i = 1; i <= n; i++) {
scanf("%s", mp[i] + 1);
for (int j = 1; j <= n; ++j) {
res[i][j] = mp[i][j] - '0';
}
}
for (int i = 1; i <= n - 1; ++i) {
for (int j = i + 1; j <= n; ++j) {
int temp = 0; //方案数
for (int k = i + 1; k <= j - 1; ++k) {
temp += res[i][k] * res[k][j];
}
res[i][j] = (temp + 1) % 10 == res[i][j];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
printf("%d", res[i][j]);
}
printf("\n");
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
int n,k,a[100009],m;
bool isok(int x)
{
int ans=0,num=0,j=1;
/*
*ans:多少个区间的第k大比mid还大 and 右端点
*num:统计有多少个数大于当前x
*j:左端点
*/
for(int i=1; i<=n; i++)//遍历A数组
{
if( a[i]>=x )
{
num++;//更新num
}
if( num==k )//说明包含当前区间的区间的第k大一定大于等于mid
{
ans+=(n-i)+1;//在 i+1 及其之后的区间大于x的点的个数都大于等于k个。
//右端点的取值
while( a[j]<x )//移动左端点
/*
*如果左端点小于x,则对第k大无影响
*/
{
ans+=n-i+1; //在 i+1 及其之后的区间大于x的点的个数都大于等于k个。
j++;
}
num--;
j++;
}
}
if(ans>=m) return true;//如果当前x符合题意
else return false;
}
signed main()
{
int t;
cin >> t;
while( t-- )
{
cin >>n>>k>>m;
int l=1e9+1,r=0;
for(int i=1; i<=n; i++)
{
cin >> a[i];
l = min(l,a[i]);
r = max(r,a[i]);
}
int ans=0;
while( r>=l )
{
int mid =(l+r)/2;
// cout <<mid <<endl;
if( isok(mid) )//如果当前x符合题意
{
l=mid+1;//二分缩短区间
ans=mid;
}
else
{
r=mid-1;//二分缩短区间
}
}
cout << ans <<endl;
}
}