分析:1001,子集异或和的异或和,除了n==1的情况外所有元素都会在偶数个子集中出现,所以特判一下即可。O(n)
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=200100;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
int main()
{
int i,n,x,t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (i=1;i<=n;i++) scanf("%d", &x);
if (n>1) printf("0\n");
else printf("%d\n", x);
}
return 0;
}
分析:1002,回文串的个数,先判断一下奇数个元素的个数来确定是否能组成回文串,再用组合数求解即可。O(n)
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=50010;
const int MOD1=1000007;
const int MOD2=100000009;
const int MAX=1000000000;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
int g[30];
ll f[1010];
char s[1010];
void ex_gcd(ll a,ll b,ll &d,ll &x,ll &y) {
if (!b) { d=a;x=1;y=0; }
else { ex_gcd(b,a%b,d,y,x);y-=x*(a/b); }
}
ll inv(ll a,ll n) {
ll d,x,y;
ex_gcd(a,n,d,x,y);
return d==1 ? (x+n)%n:-1;
}
ll get(ll x) {
ll ret=1;
for (int i=1;i<=x;i++) ret=ret*i%MOD;
return inv((ret+MOD)%MOD,MOD);
}
int main()
{
int i,t,odd,len;
ll ans;
scanf("%d", &t);
f[1]=1LL;
for (i=2;i<=1005;i++) f[i]=get(i);
while (t--) {
scanf("%s", s);
len=strlen(s);odd=0;
memset(g,0,sizeof(g));
for (i=0;i<len;i++) g[s[i]-'a'+1]++;
for (i=1;i<27;i++)
if (g[i]&1) odd++;
if (!(len&1)&&odd) { printf("0\n");continue ; }
if ((len&1)&&odd!=1) { printf("0\n");continue ; }
ans=1LL;
for (i=1;i<=len/2;i++) ans=ans*i%MOD;
for (i=1;i<27;i++)
if (g[i]/2) ans=ans*f[g[i]/2]%MOD;
printf("%d\n", (ans+MOD)%MOD);
}
return 0;
}
分析:1003,先将所有的山添加进地图,对所有平原节点做4联通并查集,然后从最后一座山开始删除,什么时候节点0和节点n*m+1联通了就输出答案即可。O(n*mlog(n*m))
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=510;
const int MAX=151;
const int mod=100000000;
const int MOD1=100000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
char s[N];
int ma[N][N],f[N*N],x[N*N],y[N*N];
int find_f(int x) {
return f[x]==x ? x:f[x]=find_f(f[x]);
}
void unio(int a,int b) {
int fa=find_f(a),fb=find_f(b);
if (fa!=fb) f[fa]=fb;
}
int main()
{
int i,j,k,q,t,n,m,sum;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
sum=n*m;memset(ma,0,sizeof(ma));
for (i=1;i<=n;i++) {
scanf("%s", s);
for (j=0;j<m;j++) ma[i][j+1]=s[j]-'0';
}
for (i=0;i<=sum+1;i++) f[i]=i;
scanf("%d", &q);
for (i=1;i<=q;i++) {
scanf("%d%d", &x[i], &y[i]);
x[i]++;y[i]++;ma[x[i]][y[i]]=1;
}
for (i=1;i<=m;i++) {
if (!ma[1][i]) unio(0,i);
if (!ma[n][i]) unio((n-1)*m+i,sum+1);
}
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (!ma[i][j]) {
k=(i-1)*m+j;
if (i>1&&!ma[i-1][j]) unio(k,k-m);
if (i<n&&!ma[i+1][j]) unio(k,k+m);
if (j>1&&!ma[i][j-1]) unio(k,k-1);
if (j<m&&!ma[i][j+1]) unio(k,k+1);
}
if (find_f(0)==find_f(sum+1)) { printf("-1\n");continue ; }
for (i=q;i;i--) {
k=(x[i]-1)*m+y[i];ma[x[i]][y[i]]=0;
if (x[i]>1&&!ma[x[i]-1][y[i]]) unio(k,k-m);
if (x[i]<n&&!ma[x[i]+1][y[i]]) unio(k,k+m);
if (y[i]>1&&!ma[x[i]][y[i]-1]) unio(k,k-1);
if (y[i]<m&&!ma[x[i]][y[i]+1]) unio(k,k+1);
if (k<=m) unio(0,k);
if (k>(n-1)*m) unio(k,sum+1);
if (find_f(0)==find_f(sum+1)) break ;
}
printf("%d\n", i);
}
return 0;
}
分析:1004,裸的DP,直接设dp[i]表示到第i个点时的最大价值。O(n^2)
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=2010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
int q[N];
db dp[N];
int main()
{
int i,j,g,n,m,t,x;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
memset(q,0,sizeof(q));
for (i=1;i<=m;i++) {
scanf("%d", &x);q[x+1]=1;
}
memset(dp,0,sizeof(dp));
for (i=1;i<=n;i++) {
g=0;
for (j=i;j>0;j--) {
if (q[j]) g++;
if (g>1) break ;
if (g==1) dp[i]=max(dp[i],dp[j-1]+log2(i-j+1));
}
}
printf("%d\n", (int)(1000000*dp[n]));
}
return 0;
}
分析:1005,排序处理完相同3元组之后就变成了经典的求区间颜色数啦。方法1:离线按询问的r排序,用树状数组维护每种3元组出现的最后位置,O(nlogn+mlogn)。方法2:维护每一个3元组出现的前一次的位置pre[i],询问区间[l,r]时只有统计pre[l]~pre[r]中有多少是小于l的即可,用可持久化线段树维护下就行了,O(nlogn+mlogn)。
代码:(树状数组)
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=200100;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
struct node {
int l,r,id;
}q[N];
struct xxx {
int x,y,z,w;
}d[N];
int n,a[N],f[N],g[N],ans[N],pre[N];
int cmd(xxx a,xxx b) {
if (a.x!=b.x) return a.x<b.x;
if (a.y!=b.y) return a.y<b.y;
if (a.z!=b.z) return a.z<b.z;
return a.w<b.w;
}
int cmd1(node a,node b) {
return a.r<b.r;
}
void add(int x,int y) {
if (x<=0) return ;
for (;x<=n-2;x+=x&(-x)) g[x]+=y;
}
int getsum(int x) {
int ret=0;
if (x<=0) return 0;
for (;x;x-=x&(-x)) ret+=g[x];
return ret;
}
int main()
{
int i,k,t,m,R;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (i=1;i<=n;i++) scanf("%d", &a[i]);
for (i=1;i<=n-2;i++) {
d[i].x=a[i];d[i].y=a[i+1];d[i].z=a[i+2];d[i].w=i;
}
sort(d+1,d+n-1,cmd);
k=0;d[0].x=d[0].y=d[0].z=-1;
for (i=1;i<=n-2;i++)
if (d[i].x<=d[i].y&&d[i].y<=d[i].z) {
if (d[i].x==d[i-1].x&&d[i].y==d[i-1].y&&d[i].z==d[i-1].z) f[d[i].w]=k;
else f[d[i].w]=++k;
} else f[d[i].w]=0;
memset(g,0,sizeof(g));
for (i=1;i<=n-2;i++) {
pre[i]=g[f[i]];g[f[i]]=i;
}
scanf("%d", &m);
for (i=1;i<=m;i++) {
scanf("%d%d", &q[i].l, &q[i].r);q[i].id=i;
}
memset(g,0,sizeof(g));
sort(q+1,q+m+1,cmd1);R=0;
for (i=1;i<=m;i++) {
while (R<q[i].r) {
R++;
if (R>2&&f[R-2]!=0) { add(pre[R-2],-1);add(R-2,1); }
}
if (q[i].r-q[i].l<2) ans[q[i].id]=0;
else ans[q[i].id]=getsum(q[i].r-2)-getsum(q[i].l-1);
}
for (i=1;i<=m;i++) printf("%d\n", ans[i]);
}
return 0;
}
代码:(可持久化线段树)
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=200100;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000009;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
struct xxx {
int x,y,z,w;
}d[N];
int a[N],f[N],pre[N];
int cmd(xxx a,xxx b) {
if (a.x!=b.x) return a.x<b.x;
if (a.y!=b.y) return a.y<b.y;
if (a.z!=b.z) return a.z<b.z;
return a.w<b.w;
}
int siz,root[20*N],ls[20*N],rs[20*N],sum[20*N];
void updata(int l,int r,int x,int &y,int z) {
y=++siz;
sum[y]=sum[x]+1;
if (l==r) return ;
ls[y]=ls[x];rs[y]=rs[x];
int mid=(l+r)>>1;
if (z<=mid) updata(l,mid,ls[x],ls[y],z);
else updata(mid+1,r,rs[x],rs[y],z);
}
int getsum(int l,int r,int x,int y,int z) {
if (r==z) return sum[y]-sum[x];
int mid=(l+r)>>1;
if (z<=mid) return getsum(l,mid,ls[x],ls[y],z);
else return sum[ls[y]]-sum[ls[x]]+getsum(mid+1,r,rs[x],rs[y],z);
}
int main()
{
int i,k,t,n,m,l,r;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (i=1;i<=n;i++) scanf("%d", &a[i]);
for (i=1;i<=n-2;i++) {
d[i].x=a[i];d[i].y=a[i+1];d[i].z=a[i+2];d[i].w=i;
}
sort(d+1,d+n-1,cmd);
k=0;d[0].x=d[0].y=d[0].z=-1;
for (i=1;i<=n-2;i++)
if (d[i].x<=d[i].y&&d[i].y<=d[i].z) {
if (d[i].x==d[i-1].x&&d[i].y==d[i-1].y&&d[i].z==d[i-1].z) f[d[i].w]=k;
else f[d[i].w]=++k;
} else f[d[i].w]=0;
memset(a,0,sizeof(a));
for (i=1;i<=n-2;i++) {
pre[i]=a[f[i]]+1;a[f[i]]=i;
if (!f[i]) pre[i]=n;
}
siz=sum[0]=root[0]=0;
for (i=1;i<=n-2;i++) updata(1,n,root[i-1],root[i],pre[i]);
scanf("%d", &m);
while (m--) {
scanf("%d%d", &l, &r);
if (r-l<2) printf("0\n");
else printf("%d\n", getsum(1,n,root[l-1],root[r-2],l));
}
}
return 0;
}