A:
我是用最拙计的方法套线段树过的。倒过来更新,每次用x覆盖掉区间[l,x-1] [x+1,r],初始全0。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
/*-------------------------Template----*/
#define N 300010
#define E 50000
#define ll long long
#define CUBE(x) ((x)*(x)*(x))
#define SQ(x) ((x)*(x))
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
#define maxAry(a,n) max_element(a,a+(n))
#define minAry(a,n) min_element(a,a+(n))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int PRIME =999983;
const int MOD =10007;
const int MULTI =1000000007;
const double EPS=1e-9;
/*----------------------end Template----*/
class segTree{
#define lson rt<<1
#define rson rt<<1|1
#define rtl seg[rt].l
#define rtr seg[rt].r
private:
struct segment{
int l,r,who,mark;
}seg[N<<2];
public:
void pushdown(int rt)
{
if(seg[rt].mark==0) return ;
seg[lson].who=seg[rt].mark;
seg[rson].who=seg[rt].mark;
seg[lson].mark=seg[rt].mark;
seg[rson].mark=seg[rt].mark;
seg[rt].mark=0;
}
void update(int who,int L,int R,int rt)
{
if(L<=rtl && rtr <=R){
seg[rt].who=who;
seg[rt].mark=who;
return ;
}
pushdown(rt);
int mid=(rtl+rtr)>>1;
if(L<=mid) update(who,L,R,lson);
if(R>mid) update(who,L,R,rson);
}
void output(int rt)
{
if(rtl==rtr){
printf("%d ", seg[rt].who);
return ;
}
pushdown(rt);
output(lson);
output(rson);
}
void build(int l,int r,int rt)
{
rtl=l,rtr=r;
seg[rt].who=0;
seg[rt].mark=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
}
}T;
int l[N],r[N],x[N];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
T.build(1,n,1);
for(int i=0;i<m;i++)
scanf("%d%d%d",&l[i],&r[i],&x[i]);
for(int i=m-1;i>=0;i--){
if(x[i]>l[i])
T.update(x[i],l[i],x[i]-1,1);
if(x[i]<r[i])
T.update(x[i],x[i]+1,r[i],1);
}
T.output(1);
puts("");
return 0;
}
我们考虑如果length(A) 与 length(B) 互质(以下记为al,bl)。那么不断复制它们,会出现循环周期,一个周期的长度是al*bl。
在一个周期内,A中任一字符都会和B中所有字符配对一次。如果al与bl不互质的话,我们可以求出最大公约数g。因为al/g和bl/g是互质的,那么我们就可以以g为单位长度来划分A,B,使其分成al/g段和bl/g段。这样A中任一段都会和B中所有段配对一次。
得出这个结论之后,我们就统计一下cnt[i%g][A[i]-'a'],对于B也统计一下,然后乘一下就是A[i]==B[i]的数量。不过只是(al/g)*(bl/g)*g长度内的,所以还要乘以n*al/((al/g)*(bl/g)*g),化简下就是n*g/bl。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
/*-------------------------Template----*/
#define N 1000010
#define E 50000
#define ll long long
#define CUBE(x) ((x)*(x)*(x))
#define SQ(x) ((x)*(x))
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
#define maxAry(a,n) max_element(a,a+(n))
#define minAry(a,n) min_element(a,a+(n))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int PRIME =999983;
const int MOD =10007;
const int MULTI =1000000007;
const double EPS=1e-9;
/*----------------------end Template----*/
char a[N],b[N];
int cnt[N][26],cb[N][26];
int gcd(int a,int b){ return b?gcd(b,a%b):a; }
int main()
{
ll n,m,al,bl,same=0;
scanf("%I64d%I64d",&n,&m);
scanf("%s%s",a,b);
al=strlen(a);
bl=strlen(b);
int g=gcd(al,bl);
for(int i=0;i<al;i++) cnt[i%g][a[i]-'a']++;
for(int i=0;i<bl;i++) same+=cnt[i%g][b[i]-'a'];
same*=n/(bl/g);
printf("%I64d\n", n*al-same);
return 0;
}
C:
贪心,很多贪法都能过,就是容易FST。我的做法是优先把2变成3,变成4的话消耗太多,可能最后不够的话还要再变回3。所以排序一下,0的忽略,然后把前面的拿到后面,使得后面的都变成3。这样最后只会剩下一个数是小于3的(忽略0),因为2 2会成为 1 3, 1 1会成为 0 2, 1 2会成为0 3,都是剩一个数小于3。然后再看最后这个数怎么调整,有两种策略,一种是把它分配到数值是3的位置,还一种是把4拿出1来,补足3。对于第一种策略,还需要注意一下细节。就是如果这个数比原来的小,说明它前面有别的人换进来,而我们现在的策略是把当前的人都分配到3的地方,那之前换进来的人可以认为直接分配到了3的地方,这样不需要再花费代价。在两种策略中取下最小。如果两种策略都无法操作,那就输出-1。
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
/*-------------------------Template----*/
#define N 1000010
#define E 50000
#define ll long long
#define CUBE(x) ((x)*(x)*(x))
#define SQ(x) ((x)*(x))
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
#define maxAry(a,n) max_element(a,a+(n))
#define minAry(a,n) min_element(a,a+(n))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int PRIME =999983;
const int MOD =10007;
const int MULTI =1000000007;
const double EPS=1e-9;
/*----------------------end Template----*/
int a[N],d[N];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]),d[i]=a[i];
sort(a,a+n);
sort(d,d+n);
// for(int i=0;i<n;i++) printf("%d ", a[i]); puts("");
int m=upper_bound(a,a+n,2)-a;
int ans=0;
for(int i=0,j=m-1;i<j;i++){
if(a[i]==0) continue;
if(++a[j]==3) j--;
if(--a[i]) i--;
ans++;
}
bool tag=true,f1=true,f2=true;
for(int i=0;a[i]<3 && i<n;i++){
if(a[i]==0) continue;
int x=a[i],sum;
for(int j=i+1;x && j<n;j++)
if(a[j]==3) x--;
if(x) f1=false;
else{
if(d[i]>a[i]) sum=a[i];
else sum=d[i];
}
x=3-a[i];
for(int j=i+1;x && j<n;j++)
if(a[j]==4) x--;
if(x) f2=false;
if(f1 || f2){
if(f1 && f2) ans+=min(sum,3-a[i]);
else if(f1) ans+=sum;
else ans+=3-a[i];
}else tag=false;
break;
}
if(tag) printf("%d", ans);
else puts("-1");
return 0;
}