CF872 Div2
A
方法一 : 暴力判断枚举子串 ,判断其是否回文 ,O( \(\frac 14n^3\))
方法二 : 整个串已知是一个回文串 ,贪心地想前 \(n - 1\) 构不构成回文串 , 若不构成 , 则答案就是 \(n - 1\)
若前 \(n - 1\) 构成回文,且 \(n\) 构成回文串 , 类似于 $s[n] = s[1] = s[n - 1] = s[2] ... $ , 全串都相同
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0) ; cout.tie(0);
int t;
cin >> t;
while(t--){
string s;
cin >> s;
map<char,bool> ma;
for(int i = 0 ; i < s.length() ; ++i)
ma[s[i]] = true;
if(ma.size() == 1) cout << "-1\n";
else cout << s.length() - 1 << '\n';
}
return 0;
}
B
考虑对全局影响最大的几个点 $ (1,1) , (1,2) , (2 , 1) $
所有 $x \geqslant 2 , y \geqslant2 $ 的矩阵均能受到 最大值 - 最小值的影响 , 那么对于 $ x\leqslant 1$ 或者 $ y\leqslant 1$ 的的矩阵只能只能选择其一(选择个数最多的行或列)受到 最大值 - 最小值的影响 ,剩下的一行或者列受到 $ max ( 最大 - 次小 , 次大 - 最小 ) $ 的影响
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
ios::sync_with_stdio(false);
cin.tie(0) ; cout.tie(0);
int t;
cin >> t;
while(t--){
int n,m;
cin >> n >> m;
vector<int> a(n * m);
for(int i = 0 ; i < n * m ; ++i)
cin >> a[i];
sort(a.begin(),a.end());
if(n < m) swap(n , m);
ll ans = 1ll * (a[n * m - 1] - a[0]) * (n * m - m) + 1ll * (m - 1) * max(a[n * m - 1] - a[1] , a[n * m - 2] - a[0]);
cout << ans << '\n';
}
return 0;
}
C
考虑可以 确定的位置 和 不确定位置( \(-1 , -2\) )的优先级问题 , 确定位置 对于 不确定位置 的影响是不确定位置只能放在 确定位置(最左 , 最右)的左边和右边 , 不确定位置 对于 确定位置 的影响 是 不确定位置 会占据确定位置 , 这里我们应该会想到经典的 "填充" 的策略 , 固定一个位置 x , 往它左右两边填确定位置 , 确定位置中间填充 不确定位置 即可 , 这样坐标递增递减地填尽可能地减少了 "最左" , "最右"限制的影响.
同时要考虑其他情况 : 一开始填 \(-1\) 或 \(-2\)
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0) ; cout.tie(0);
int t;
cin >> t;
while(t--){
int n,m;
cin >> n >> m;
vector<int> a(n) , b;
int res1 = 0 , res2 = 0 , ans;
for(int i = 0 ; i < n ; ++i){
cin >> a[i];
if(a[i] == -1) ++res1;
else if(a[i] == -2) ++res2;
else b.push_back(a[i]);
}
sort(b.begin(),b.end());
b.erase(unique(b.begin(),b.end()),b.end());
ans = min(max(res1 , res2) + (int)b.size() , n); //一开始填 -1 或者 -2
for(int i = 0 ;i < b.size() ; ++i){
int l = b[i] - 1 , r = m - b[i]; // 从中间向两边填
l = min(l , i + res1) , r = min(r , (int)b.size() - 1 - i + res2);
ans = max(ans , l + r + 1);
}
cout << min(ans , m) << '\n';
}
}
D
对于 \(k = 1\) , 只能是特殊点自己 , 期望就是 \(1\)
对于 \(k = 2\) , 发现好点只能在两点所在的链上
对于 \(k = 3\) , 先确定任意两点的链 , 发现从剩余那个点到这条链的路径上 , 靠近路径一步 , 那么靠经两个点一步 , 远离剩余点一步 , 那么 $ ans = ans - 2 + 1 = ans - 1 $ , 答案会变小 , 那么最优点就是来的路径和链的交点 (再试试在链上走发现远离剩余点,但两点距离不变 , 答案更差了) , 那么期望也是 \(1\)
那么对于第二种情况 , 只有一个点在链上它就会产生 \(1\) 的贡献 , 那么考虑任选两个点形成的链经过它的概率就好了
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5+5 , M = N * 2;
const ll mod = 1e9+7 , inv2 = 500000004;
int n,k;
int head[N],ver[M],nxt[M],tot;
ll sz[N],p,f[N];
void add(int x,int y)
{
ver[++tot] = y , nxt[tot] = head[x] , head[x] = tot;
}
ll ksm(ll a, ll b , ll mod){
ll base = a % mod , ans = 1;
while(b){
if(b & 1) ans = ans * base % mod;
base = base * base % mod;
b>>=1;
}
return ans;
}
void dfs(int x,int fa)
{
sz[x] = 1;
for(int k = head[x] ; k ; k = nxt[k])
{
int y = ver[k];
if(y == fa) continue;
dfs(y , x);
sz[x] += sz[y];
}
ll pre_sum = 0;
for(int k = head[x] ; k ; k = nxt[k])
{
int y = ver[k];
if(y == fa) continue;
//此时枚举的链 , x 一定不为头或者尾
f[x] += (n - sz[x]) * sz[y] % mod , f[x] %= mod; // 子与祖先
if(pre_sum == 0) pre_sum = sz[y];
else {
f[x] += pre_sum * sz[y] % mod , f[x] %= mod;
pre_sum += sz[y] , pre_sum %= mod;
//子与子之间
// presum 的作用 , 类似于树上背包,保留之前出现过的兄弟的个数
}
}
f[x] += (n - 1) , f[x] %= mod; //链以 x 为头或者尾
}
int main()
{
scanf("%d %d",&n,&k);
for(int i = 1 ; i < n ; ++i){
int x,y;
scanf("%d %d",&x,&y);
add(x , y) , add(y , x);
}
if(k & 1){
cout << "1\n";
return 0;
}
ll p = 1ll * n * (n - 1) % mod * inv2 % mod; //这里 wa 了一次 , 少了 1ll
p = ksm(p , mod - 2 , mod); // 1 / C(n , 2);
dfs(1 , 0);
ll ans = 0;
for(int i = 1 ; i <= n ; ++i)
ans += f[i] , ans %= mod;
cout << ans * p % mod << '\n';
}
E
\(D\) 的增强版本 , 此时 \(k\) 为任意数
大胆猜测 , \(D\) 中的 \(1,3\) 答案均是 \(1\) , 那么是不是 \(k\) 为奇数的话 , 答案均为 \(1\)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
const int N = 2e5+5 , M = N * 2;
ll n,k;
int head[N],ver[M],nxt[M],tot;
ll sz[N],jc[N];
void add(int x,int y)
{
ver[++tot] = y , nxt[tot] = head[x] , head[x] = tot;
}
ll ksm(ll a , ll b , ll mod)
{
a %= mod;
ll ans = 1;
while(b){
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll C(ll n , ll m)
{
if(m > n) return 0;
ll up = jc[n] , down = jc[m] * jc[n - m] % mod;
down = ksm(down , mod - 2 , mod);
return up * down % mod;
}
void dfs(int x,int fa,ll &ans)
{
sz[x] = 1;
for(int i = head[x] ; i ; i = nxt[i])
{
int y = ver[i];
if(y == fa) continue;
dfs(y , x , ans);
sz[x] += sz[y];
ans += C(n - sz[y] , k / 2) * C(sz[y] , k / 2) % mod , ans %= mod;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0) ; cout.tie(0);
cin >> n >> k;
for(int i = 1 ; i < n ; ++i){
int x,y;
cin >> x >> y;
add(x , y) , add(y , x);
}
if(k & 1) {
cout << "1\n";
return 0;
}
jc[0] = 1;
for(int i = 1 ; i <= n ; ++i)
jc[i] = jc[i - 1] * i % mod;
ll ans = 0;
dfs(1 , 0 , ans);
ll p = C(n , k);
p = ksm(p , mod - 2 , mod);
ans = ans * p % mod;
cout << (ans + 1) % mod << '\n';
return 0;
}

浙公网安备 33010602011771号