二进制状态压缩,判断相同对数sum,总对数
#include<bits/stdc++.h>
using namespace std;
const int MAX=1025;
int a[MAX];//二进制串
int num[MAX];
int main()
{
int t,n,m,K;
char str[11];
scanf("%d",&t);
for(int tc=1;tc<=t;tc++)
{
memset(a,0,sizeof(a));
scanf("%d%d%d",&n,&m,&K);
for(int i=0;i<n;i++)
{
scanf("%s",str);
for(int j=0;j<m;j++)
if(str[j]=='B') a[i]+=1<<j;
}
if(n==1) {printf("Case #%d: 0\n",tc);continue;}
int ans=0;
for(int i=1;i<(1<<m);i++)
{
memset(num,0,sizeof(num));
for(int j=0;j<n;j++)
{
int x=a[j]&i;
num[x]++;
}
int K0=0;
for(int j=0;j<(1<<m);j++)
K0+=num[j]*(num[j]-1)/2;
if(K0<=n*(n-1)/2-K) ans++;
}
printf("Case #%d: %d\n",tc,ans);
}
return 0;
}
字典序满足 “abc”>"a";"b">"a";所有长度子串中单个字母字典序最小
线段树维护区间最小值的个数
#include<stdio.h>
#include<string.h>
#include<math.h>
const int MAX=1e5+5;
char str[MAX];
struct node
{
char a;
int b;
node(){a='Z';b=0;}
node(node& x){a=x.a;b=x.b;}
}c[MAX*4];
void build(int rt,int l,int r)
{
if(l==r)
{
c[rt].a=str[l-1];
c[rt].b=1;
return ;
}
int mid=(l+r)>>1;
build(rt*2,l,mid);
build(rt*2+1,mid+1,r);
if(c[rt*2].a==c[rt*2+1].a){c[rt]=c[rt*2];c[rt].b+=c[rt*2+1].b;}
else if(c[rt*2].a<c[rt*2+1].a) c[rt]=c[rt*2];
else c[rt]=c[rt*2+1];
}
node query(int rt,int l,int r,int L,int R)
{
if(L<=l&&R>=r) return c[rt];
int mid=(l+r)>>1;
node x,y;
if (L<=mid) x=query(rt*2,l,mid,L,R);
if (R>mid) y=query(rt*2+1,mid+1,r,L,R);
if(x.a==y.a) x.b+=y.b;
else if(x.a>y.a) x=y;
return x;
}
int main()
{
int t,n,q,l,r;
scanf("%d",&t);
for(int tc=1;tc<=t;tc++)
{
printf("Case #%d:\n",tc);
scanf("%d%d",&n,&q);
scanf("%s",str);
build(1,1,n);
while(q--)
{
scanf("%d%d",&l,&r);
printf("%d\n",query(1,1,n,l,r).b);
}
}
return 0;
}
动态规划状态转移方程:
dp[ i ][ j ]表示序列长度为i取到第j个数时的种类数
用树状数组维护取到第j个数时的a[ j ]前缀和( a[ j ]的前缀和中必定不包含a[ k ],a[ k ]>a[ j ] ),同时满足 j > k且a[ j ] > a[ k ]的单调性
把求和过程的复杂度优化到O(logn)
滚动数组优化内存
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e4+5;
const long long MOD=1e9+7;
int a[MAX],n;
long long dp[2][MAX];
long long c[MAX],ans[MAX];
void add(int x,int v)
{
while(x<=n){c[x]=(c[x]+v)%MOD;x+=x&-x;}
}
long long get(int x)
{
long long sum=0;
while(x){sum=(sum+c[x])%MOD;x-=x&-x;}
return sum;
}
int main()
{
int t;
scanf("%d",&t);
for(int tc=1;tc<=t;tc++)
{
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(int i=1;i<=n;i++) {scanf("%d",&a[i]);}
for(int i=1;i<=n;i++) dp[1][i]=1;ans[1]=n;
for(int i=2;i<=n;i++)
{
ans[i]=0;
if(ans[i-1]==0) continue;
memset(c,0,sizeof(c));
for(int j=1;j<=n;j++)
{
dp[i%2][j]=get(a[j]-1);
add(a[j],dp[(i-1)%2][j]);
ans[i]=(ans[i]+dp[i%2][j])%MOD;
}
}
printf("Case #%d:",tc);
for(int i=1;i<=n;i++) printf(" %I64d",ans[i]);
putchar('\n');
}
return 0;
}
Kruskal计算最小生成树权值,优先队列维护最小边权
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e2+5;
const int INF=0x3f3f3f3f;
int f[MAX],tot1,tot2;
struct Edge
{
int a,b,w;
Edge(){}
Edge(int a_,int b_,int v_)
{
a=a_;b=b_;w=v_;
}
Edge(const Edge &e)
{
a=e.a;b=e.b;w=e.w;
}
}e1[MAX],e2[MAX];
int q1[MAX],q2[MAX],L1,R1,L2,R2;
void add1(Edge &e)
{
e1[tot1++]=e;
}
void add2(Edge &e)
{
e2[tot2++]=e;
}
int find(int x)
{
if(f[x]==-1) return x;
else return f[x]=find(f[x]);
}
bool cmp(Edge &ea,Edge &eb)
{
return ea.w<eb.w;
}
int kurskal1(int n)
{
memset(f,-1,sizeof(f));
sort(e1,e1+tot1,cmp);
int cnt=0,ans=0;
for(int i=0;i<tot1;i++)
{
int u=e1[i].a;
int v=e1[i].b;
int w=e1[i].w;
if(cnt==n-1)
{
q1[++R1]=w;
continue;
}
int t1=find(u);
int t2=find(v);
if(t1!=t2)
{
ans+=w;
f[t1]=t2;
cnt++;
}
else q1[++R1]=w;
}
sort(q1,q1+R1+1);
if(cnt<n-1) return INF;
else return ans;
}
int kurskal2(int n)
{
memset(f,-1,sizeof(f));
sort(e2,e2+tot2,cmp);
int cnt=0,ans=0;
for(int i=0;i<tot2;i++)
{
int u=e2[i].a;
int v=e2[i].b;
int w=e2[i].w;
if(cnt==n-1)
{
q2[++R2]=w;
continue;
}
int t1=find(u);
int t2=find(v);
if(t1!=t2)
{
ans+=w;
f[t1]=t2;
cnt++;
}
else q2[++R2]=w;
}
sort(q2,q2+R2+1);
if(cnt<n-1) return INF;
else return ans;
}
int main()
{
int t,n,m,x,y,v;
char s[5];
scanf("%d",&t);
for(int tc=1;tc<=t;tc++)
{
tot1=tot2=0;
L1=L2=0;
R1=R2=-1;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d%d%d%s",&x,&y,&v,s);
Edge e(x,y,v);
if(s[0]=='G') {add1(e);add2(e);}
else if(s[0]=='R') {add1(e);q2[++R2]=v;}
else {add2(e);q1[++R1]=v;}
}
int a1=kurskal1(n),a2=kurskal2(n);
printf("Case #%d:\n",tc);
for(int i=1;i<n-1;i++) printf("-1\n");
for(int i=n-1;i<=m;i++)
{
int ans=min(a1,a2);
if(ans>=INF) printf("-1\n");
else printf("%d\n",ans);
int as1=INF,as2=INF;
if(L1<=R1) as1=q1[L1++];
if(L2<=R2) as2=q2[L2++];
a1=a1+as1;
a2=a2+as2;
}
}
return 0;
}