C. You Soared Afar With Grace
题目大意:给你一个2行n列的二维数组,问你能否通过交换两列元素的方法,对于每个 i=1,2,…,ni=1,2,…,n , ai=bn+1−i,如果能写出其具体操作步骤,不能就输出-1
#1 每次必须交换1列元素,所以对于两列元素,必须有{ai,bi},{bi,ai}
#2 n为奇数时,中间可以插一个
思路:首先记录ai = bi 和 有ai,bi但无bi,ai的数量,大于1就不能构造出,为1就可以把他换到中间,且只有一个时,n时一定时奇数的
代码:
void solve()
{
int n;
cin >> n;
vector<PII> v(n+1);
map<PII,int> mp;
for (int i = 1; i <= n; i ++ ) cin >> v[i].x;
for (int i = 1; i <= n; i ++ ) cin >> v[i].y;
for (int i = 1; i <= n; i ++ ) mp[{v[i].x,v[i].y}] = i;
int cnt = 0,pos = 1;
for (int i = 1; i <= n; i ++ )
if (v[i].x == v[i].y || !mp.count({v[i].y,v[i].x}))
cnt ++ , pos = i;
if (cnt > 1)
{
cout<<-1<<endl;
return ;
}
vector<PII> ans;
function<void(int,int)> sp = [&](int x,int y) -> void
{
ans.emplace_back(x,y);
mp[v[x]] = y, mp[v[y]] = x;
swap(v[x],v[y]);
};
if (cnt == 1 && pos != (n+1)/2) sp(pos,(n+1)/2);
for (int i = 1; i <= n / 2; i ++ )
{
int p = mp[{v[i].y,v[i].x}];
if (p != n - i + 1)
sp(p,n - i + 1);
}
cout<<ans.size()<<endl;
for (auto it = ans.begin(); it != ans.end(); it ++ )
cout<<it->x<<" "<<it->y<<endl;
}
C. Saraga
题目大意:给定两个字符串,让你构造出一个字符串,使至少有两种方法将该字符串分为非空的两串,这两串分属于第一个字符串的前缀,和第二个字符串的后缀
#1 第一串的首字母和第二串的尾字母是不动的
思路:贪心靠右记录字符串2中每个字符出现的位置,除1串首字符和2串尾字符外,只要有1个公共字符即满足条件,我们构造出的字符串即为1串到该字符和2串中该字符到末尾,最后从左到右遍历一遍即可
代码:
void solve()
{
string s1,s2; cin >> s1 >> s2;
map<char,int> mp;
int n1 = s1.size(), n2 = s2.size();
s1 = ' ' + s1, s2 = ' ' + s2;
for (int i = 1; i < n2; i ++ )
mp[s2[i]] = i;
int ans = 1e9;
string s = "";
for (int i = 2; i <= n1; i ++ )
if (mp.count(s1[i]))
{
if (ans > i + n2 - mp[s1[i]])
{
ans = i + n2 - mp[s1[i]];
s = s1.substr(1,i) + s2.substr(mp[s1[i]]+1);
}
ans = min(ans,i + n2 - mp[s1[i]] );
}
if (ans == 1e9) s = "-1";
cout<<s<<endl;
}
D. Satyam and Counting
题目大意:给你一堆坐标,让你计算这一堆中有多少个由不同的三个点组成的直角三角形
#1 纵坐标是0和1
#2 思考怎么构造出直角三角形
思路:第一种情况,有(x,0)和(x,1)两点,则该两点可以和除这两点外的所有点组成直角三角形,第二种情况,有(x,0)点时另有(x-1,1),(x+1,1)两点则可组成,(x,1)情况则与之对应
代码:
void solve()
{
int n; cin >> n;
vector<array<int,2>> v(n+1);
vector<PII> d(n);
map<int,int> mp1, mp2;
for (int i = 0; i < n; i ++ )
{
cin >> d[i].x >> d[i].y;
v[d[i].x][d[i].y] ++ ;
if (d[i].y == 0) mp1[d[i].x] ++ ;
if (d[i].y == 1) mp2[d[i].x] ++ ;
}
i64 ans = 0;
for (int i = 0; i <= n; i ++ )
{
if (v[i][0] + v[i][1] == 2) ans += n - 2;
}
for (int i = 0; i < n; i ++ )
{
if (d[i].y == 0)
{
if (mp2.count(d[i].x-1) && mp2.count(d[i].x+1)) ans ++ ;
}
else
{
if (mp1.count(d[i].x-1) && mp1.count(d[i].x+1)) ans ++ ;
}
}
cout<<ans<<endl;
}
F. Sakurako's Box
题目大意:给你数组a1,a2...an,让你求a1*a2+a1*a3+...+a(n-1)*an/(n*(n-1)/2)mod(1e9+7)的值
#1 费马小定理求逆元
#2 考虑推公式
思路:该公式可推为
注意爆int即可
代码:
i64 qmi(i64 a,int b,int p)
{
i64 res = 1 % p;
while (b)
{
if (b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
void solve()
{
int n;
cin >> n;
vector<i64> v(n+1),pre(n+1);
for (int i = 1; i <= n; i ++ ) cin >> v[i];
for (int i = 1; i <= n; i ++ )
pre[i] = pre[i-1] + v[i];
i64 res = 0;
for (int i = 1; i <= n - 1; i ++ )
{
res = (v[i]*((pre[n] - pre[i])%M)+res)%M;
}
cout<<res * qmi((i64)n*(n-1)/2%M,M-2,M)%M<<endl;
}