A
题意:给定长度为n的数组,问有多少对(i,j)满足|a[i]-a[j]|=max|a[p]-q[q]|(1<=p,q<=n).
思路:求最大值的个数cnt1和最小值个数cnt2,注意当最大值等于最小值时,答案为n*(n-1);否则为2*cnt1*cnt2
#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ios cin.sync_with_stdio(false)
#define PII pair<int,int>
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;
using namespace std;
int n;
int a[N];
void solve()
{
int ma=-inf,mi=inf;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
ma=max(ma,a[i]);
mi=min(mi,a[i]);
}
int cnt1=0,cnt2=0;
for(int i=1;i<=n;i++)
{
if(a[i]==ma) cnt1++;
if(a[i]==mi) cnt2++;
}
if(cnt1==cnt2&&cnt1==n) cout<<(ll)n*(n-1)<<'\n';
else cout<<(ll)2*cnt1*cnt2<<'\n';
}
int main()
{
//ios;
int _t=1;
cin>>_t;
while(_t--) solve();
system("pause");
return 0;
}
B
题意:给定n和m,n个人编号1~n站成一排,m对关系,每队关系给定x和y,表示x号人和y号人不认识,问有多少个区间[l,r]满足区间内所有人都相互认识。
思路:处理每个人右边第一个不认识的人的位置。注意若a[i]=j,而在i和j之间可能还有x和y互相不是朋友(a[x]=y,且i<x<y<j),这样a[i]的贡献就不是j-i了,就应该是y-i,这样的话不妨让a[i]=y
#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ios cin.sync_with_stdio(false)
#define PII pair<long long,long long>
#define int long long
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;
using namespace std;
int n,m;
int a[N];
void solve()
{
cin>>n>>m;
for(int i=1;i<=n;i++) a[i]=n+1;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
if(x>y) swap(x,y);
a[x]=min(a[x],y);
}
for(int i=n-1;i>=1;i--)//减少无效段数
a[i]=min(a[i],a[i+1]);
ll ans=0;
for(int i=1;i<=n;i++)
ans+=a[i]-i;
cout<<ans<<'\n';
}
signed main()
{
//ios;
int _t=1;
cin>>_t;
while(_t--) solve();
system("pause");
return 0;
}
C
题意:给定长度为n的数组,问这些数中是否存在不互质的两个数,存在YES,不存在NO
思路:预处理1e5内的质数,map记录每个因子是否出现过。
#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ios cin.sync_with_stdio(false)
#define PII pair<int,int>
#define int long long
typedef long long ll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;
using namespace std;
bool st[N];
int primes[N],cnt;
void get_primes(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]<=n/i;j++)
{
st[primes[j]*i]=1;
if(i%primes[j]==0) break;
}
}
}
int n;
int a[N];
void solve()
{
cin>>n;
bool f=0;
map<int,bool>mp;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(f) continue;
for(int j=0;j<cnt&&primes[j]*primes[j]<=a[i];j++)
{
if(a[i]%primes[j]==0)
{
if(mp[primes[j]]) {f=1;break;}
while(a[i]%primes[j]==0) a[i]/=primes[j];
mp[primes[j]]=1;
}
}
if(a[i]!=1)
{
if(mp[a[i]]) f=1;
mp[a[i]]=1;
}
}
if(f) puts("YES");
else puts("NO");
}
signed main()
{
//ios;
get_primes(N);
int _t=1;
cin>>_t;
while(_t--) solve();
system("pause");
return 0;
}
D
Hossam and (sub-)palindromic tree
题意:给你n个点的树,树上节点是一个字符,问树上两点间简单路径形成的最长回文子序列的长度
思路:先考虑求一个字符串的最长回文子序列的长度,可以考虑动态规划,f[i][j]表示从第i个字符到第j个字符的最长回文子序列长度,那么,状态转移为:
若s[i]==s[j]:f[i][j]=2+f[i+1][j-1]
若s[i]!=s[j]:f[i][j]=max( f[i+1][j], f[i][j-1])
我们可以在O(n^2)的时间复杂度内解决
再来考虑如何在树上求,例如当我们求节点1到节点5的最长回文子序列时,先看节点1和节点5代表的字符是否相同,相同时,结果变成2+节点3到节点4之间的最长回文子序列;不同时,结果变成max(节点1到节点4,节点3到节点5),可以采用记忆化搜索,时间复杂度O(n^2).我们可以在dfs的过程中记录每个节点的父节点,用栈记录从根节点到该节点的路径。
#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
#define ios cin.sync_with_stdio(false)
#define PII pair<int,int>
typedef long long ll;
const int N=2e3+10;
const int inf=0x3f3f3f3f;
using namespace std;
int n;
int h[N],e[2*N],ne[2*N],idx;
char s[N];
int fa[N];
int f[N][N];//从节点i到节点j的最长回文子序列长度
int st[N],tt;//栈记录从根节点到该节点的路径
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x,int ffa)
{
fa[x]=ffa;
f[x][x]=1;
st[++tt]=x;
for(int i=tt-2;i>=1;i--)
{
if(s[x]==s[st[i]]) f[x][st[i]]=f[st[i]][x]=2+f[fa[x]][st[i+1]];
else f[x][st[i]]=f[st[i]][x]=max(f[x][st[i+1]],f[fa[x]][st[i]]);
}
for(int i=h[x];~i;i=ne[i])
{
int j=e[i];
if(j==ffa) continue;
if(s[j]==s[x]) f[x][j]=f[j][x]=2;
else f[x][j]=f[j][x]=1;
dfs(j,x);
}
--tt;
}
int fun(int x,int y)//求节点x与节点y之间的最长回文子序列长度
{
if(f[x][y]!=-1) return f[x][y];
else if(s[x]==s[y]) return f[x][y]=fun(fa[x],fa[y])+2;
else return f[x][y]=max(fun(fa[x],y),fun(x,fa[y]));
}
void solve()
{
cin>>n;
for(int i=0;i<=n;i++) h[i]=-1,fa[i]=-1;
idx=0;
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
f[i][j]=-1;
tt=0;
scanf("%s",s+1);
for(int i=1;i<=n-1;i++)
{
int a,b;
cin>>a>>b;
add(a,b);add(b,a);
}
dfs(1,-1);
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
ans=max(ans,fun(i,j));
cout<<ans<<'\n';
}
int main()
{
//ios;
int _t=1;
cin>>_t;
while(_t--) solve();
system("pause");
return 0;
}