统计一下最小和最大值的个数分别是多少,则 a n s = 2 ∗ c n t m i n ∗ c n t m a x ans=2*cnt_{min}*cnt_{max} ans=2∗cntmin∗cntmax,如果最大值等于最小值, a n s = 2 ∗ n ∗ ( n − 1 ) ans=2*n*(n-1) ans=2∗n∗(n−1)
#include
#include
#include
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 1000005
#define int long long
using namespace std;
using namespace __gnu_pbds;
cc_hash_table<int,int>mp;
int read() {
int x=1,res=0;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') x=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
res=res*10+(c-'0');
c=getchar();
}
return res*x;
}
void solve() {
int n=read(),ma=0,mi=1e9,cnt1=0,cnt2=0;
vector<int>a(n+1);
for(int i=1;i<=n;i++) {
a[i]=read();
ma=max(ma,a[i]);
mi=min(mi,a[i]);
}
for(int i=1;i<=n;i++) {
if(a[i]==ma) cnt1++;
if(a[i]==mi) cnt2++;
}
if(ma==mi) cout<<n*(n-1)<<'\n';
else cout<<cnt1*cnt2*2<<'\n';
}
signed main()
{
int t=read();
while(t--) solve();
return 0;
}
对每一个左端点,维护他最远能到的右端点即可。
#include
#include
#include
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 1000005
#define int long long
using namespace std;
using namespace __gnu_pbds;
cc_hash_table<int,int>mp;
int read() {
int x=1,res=0;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') x=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
res=res*10+(c-'0');
c=getchar();
}
return res*x;
}
struct node
{
int l,r;
}g[maxn];
void solve() {
int n=read(),m=read();
vector<int>l(n+1),r(n+1);
for(int i=1;i<=m;i++) {
g[i].l=read();g[i].r=read();
if(g[i].l>g[i].r) swap(g[i].l,g[i].r);
}
sort(g+1,g+1+m,[&](node a,node b){return a.l<b.l;});
int now=m,mi=n,ans=0;
for(int i=n;i>=1;i--) {
while(now>=1&&g[now].l>=i) {
mi=min(mi,g[now].r-1);
now--;
}
ans+=(mi-i+1);
}
cout<<ans<<'\n';
}
signed main()
{
int t=read();
while(t--) solve();
return 0;
}
分解质因数,然后把所有分解出的质因子放到一个map里面判重即可。
#include
#include
#include
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 1000005
#define int long long
using namespace std;
using namespace __gnu_pbds;
int read() {
int x=1,res=0;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') x=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
res=res*10+(c-'0');
c=getchar();
}
return res*x;
}
struct node
{
int l,r;
}g[maxn];
int p[maxn],cnt;
void solve() {
int n=read(),pd=0;
cc_hash_table<int,int>mp;
vector<int>a(n+1);
for(int i=1;i<=n;i++) {
a[i]=read();
for(int j=1;j<=4e3;j++) {
if(p[j]*p[j]>a[i]) break;
if(a[i]%p[j]==0) {
while(a[i]%p[j]==0) a[i]=a[i]/p[j];
if(mp[p[j]]!=0) pd=1;
mp[p[j]]=1;
}
}
if(a[i]==1) continue;
if(mp[a[i]]!=0) pd=1;
mp[a[i]]=1;
}
if(pd==1) puts("YES");
else puts("NO");
}
int vis[maxn];
signed main()
{
for(int i=2;i<=1e5;i++) {
if(!vis[i]) p[++cnt]=i;
for(int j=i*i;j<=1e5;j+=i) {
vis[j]=1;
}
}
int t=read();
while(t--) solve();
return 0;
}
先考虑区间版本的最长回文子序列求法,设 f i , j f_{i,j} fi,j表示区间 [ i , j ] [i,j] [i,j]的最长回文子序列的长度,则 f i , j = m a x { f i + 1 , j − 1 , a i ≠ a j f i + 1 , j − 1 + 2 , a i = a j f i + 1 , j f i , j − 1 f_{i,j}=max \left\{\begin{matrix} f_{i+1,j-1},~~~~~~~~~a_i\neq a_j \\ f_{i+1,j-1}+2,~~a_i=a_j \\ f_{i+1,j}~~~~~~~~~~~~~~~~~~~~~~~~~~~ \\ f_{i,j-1}~~~~~~~~~~~~~~~~~~~~~~~~~~~ \end{matrix}\right. fi,j=max⎩⎪⎪⎨⎪⎪⎧fi+1,j−1, ai=ajfi+1,j−1+2, ai=ajfi+1,j fi,j−1
然后我们可以把这个dp放在树上进行,我们只需要把树上 n 2 n^2 n2条链按照序列的方法进行 d p dp dp即可,这样我们抽出树上的一条链的时候,只需要记录前驱和后继结点即可,另外用记忆化搜索可以很方便的的实现。
#include
#include
#include
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 3005
#define int long long
using namespace std;
using namespace __gnu_pbds;
int read() {
int x=1,res=0;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') x=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
res=res*10+(c-'0');
c=getchar();
}
return res*x;
}
char a[maxn];
int nt[maxn],lt[maxn],f[maxn][maxn];
int cal(int l,int r) {
if(f[l][r]) return f[l][r];
if(nt[l]==r&&a[l]==a[r]) {return f[l][r]=2;}
if(nt[l]==r&&a[l]!=a[r]) {return f[l][r]=1;}
if(l==r) {return f[l][r]=1;}
if(a[l]==a[r]) f[l][r]=max(f[l][r],cal(nt[l],lt[r])+2);
f[l][r]=max(f[l][r] , cal(nt[l],r));
f[l][r]=max(f[l][r] , cal(l,lt[r]));
return f[l][r];
}
void solve() {
int n=read(),ans=1;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=0;
cin>>a+1;
vector<int>de(n+1);
vector<vector<int>>g(n+1);
function<void(int,int,int)>dfs=[&](int x,int fa,int root) {
if(de[x]==1) {ans=max(ans,cal(root,x));}
for(int i:g[x]) {
if(i!=fa) {
nt[x]=i;lt[i]=x;
dfs(i,x,root);
}
}
};
for(int i=1;i<n;i++) {
int aa=read(),bb=read();
g[aa].push_back(bb);
g[bb].push_back(aa);
de[aa]++;de[bb]++;
}
for(int i=1;i<=n;i++) {
if(de[i]!=1) continue;
dfs(i,0,i);
}
cout<<ans<<'\n';
}
signed main()
{
int t=read();
while(t--) solve();
return 0;
}
题目大意:计算含有最多一个medium点并且不含任何bad点的H形状的连通块最多含有多少方格。
我们可以枚举两条竖线出现的位置,然后考虑两条竖线中出现m或者不出现m的两种情况。
对于两条竖线中出现一次m的情况,我们可以枚举m出现的位置然后上下扩展,得到每个m所属的区间后,再遍历这个区间判断中间的横是否全都是好点。
对于两条竖线中不出现m的情况,我们可以直接通过双指针的方法得到区间,再判断中间的横线是否出现m的次数小于等于1次。
#include
#include
#include
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 1000005
#define int long long
using namespace std;
using namespace __gnu_pbds;
cc_hash_table<int,int>mp;
int read() {
int x=1,res=0;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') x=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
res=res*10+(c-'0');
c=getchar();
}
return res*x;
}
signed main()
{
int n=read(),m=read(),ans=0;
vector a(n+1,vector<int>(m+1));
vector sum(n+1,vector<int>(m+1));
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
char x;cin>>x;
if(x=='.') a[i][j]=0;
if(x=='m') a[i][j]=1;
if(x=='#') a[i][j]=2;
sum[i][j]=sum[i][j-1]+a[i][j];
}
}
// cout<<"ok"<
for(int i=1;i<=m;i++) {
for(int j=i+2;j<=m;j++) {
for(int l=1;l<=n;l++) {
if(a[l][i]==0&&a[l][j]==0) {
int r=l;
while(r+1<=n&&a[r+1][i]==0&&a[r+1][j]==0) r++;
if(r-l<2) continue;
for(int s=l+1;s<r;s++) {
if(sum[s][j-1]-sum[s][i]<=1)ans=max(ans,j-i-1+2*(r-l+1));
// ans+=(s-l)*(r-s);
}
l=r+1;
}
}
for(int x=1;x<=n;x++) {
if(a[x][i]+a[x][j]!=1) continue;
int l=x,r=x;
while(l-1>=1&&a[l-1][i]==0&&a[l-1][j]==0) l--;
while(r+1<=n&&a[r+1][i]==0&&a[r+1][j]==0) r++;
if(r-l<2) continue;
for(int s=l+1;s<r;s++) {
if(sum[s][j-1]-sum[s][i]==0)
ans=max(ans,j-i-1+2*(r-l+1));
// if(s<=x) ans+=(s-l)*(r-x);
// else ans+=(x-l)*(r-s);
}
}
}
}
// cout<<"ok";
cout<<ans<<"\n";
return 0;
}
出现奇数次可以用异或和不等于零代替,然后我们对于每一个数随机一个对应的值,这样只需要用主席树就能求得最小的出现次数为奇数的数字。
#include
#include
#define time chrono::system_clock::now().time_since_epoch().count()
#include
#define clean(x) memset(x,0,sizeof(x))
#define fil(x,n) fill(x,x+1+n,0)
#define inf 2000000009
#define maxn 400005
// #define int long long
using namespace std;
using namespace __gnu_pbds;
mt19937_64 rnd(time);
cc_hash_table<int,int>mp;
int read() {
int x=1,res=0;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') x=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
res=res*10+(c-'0');
c=getchar();
}
return res*x;
}
struct tr {
int l,r;
unsigned long long val;
}t[maxn*20];
int root[maxn],cnt;
void build(int &k,int l,int r) {
if(!k) k=++cnt;
if(l==r) return;
int mid=(l+r)>>1;
build(t[k].l,l,mid);
build(t[k].r,mid+1,r);
}
void modify(int &k,int l,int r,int x,int val,int lt) {
if(!k) k=++cnt;
if(l==r) {t[k].val=(val^t[lt].val);return;}
int mid=(l+r)>>1;
if(x<=mid) {
t[k].r=t[lt].r;
modify(t[k].l,l,mid,x,val,t[lt].l);
}
else {
t[k].l=t[lt].l;
modify(t[k].r,mid+1,r,x,val,t[lt].r);
}
t[k].val=t[t[k].l].val^t[t[k].r].val;
}
int query(int k,int l,int r,int lt) {
if(l==r) {
return l;
}
int mid=(l+r)>>1;
if(t[t[k].l].val!=t[t[lt].l].val) return query(t[k].l,l,mid,t[lt].l);
else return query(t[k].r,mid+1,r,t[lt].r);
}
signed main()
{
int n=read();
vector<int>a(n+1),b(n+1);
vector<unsigned long long>v(n+1);
for(int i=1;i<=n;i++) {
b[i]=a[i]=read();
}
sort(b.begin()+1,b.end());
int m=unique(b.begin()+1,b.end())-b.begin()-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b.begin()+1,b.begin()+1+m,a[i])-b.begin();
for(int i=1;i<=m;i++) v[i]=rnd();
build(root[0],1,m);
// cout<
for(int i=1;i<=n;i++) {
modify(root[i],1,m,a[i],v[a[i]],root[i-1]);
}
int q=read(),ans=0;
while(q--) {
int l=read(),r=read();
l^=ans;r^=ans;
// cout<
if(t[root[r]].val==t[root[l-1]].val) ans=0;
else ans=b[query(root[r],1,m,root[l-1])];
cout<<ans<<'\n';
}
return 0;
}