T1:不想说…
T2:给一个R,G,B构成的序列,长度3n,各有n个
分给n个人,位置为a,b,c的话
答案为求
∑
m
a
x
(
a
,
b
,
c
)
−
m
i
n
(
a
,
b
,
c
)
\sum max(a,b,c)-min(a,b,c)
∑max(a,b,c)−min(a,b,c)为最小值时的方案数
n
⩽
1
0
5
n\leqslant 10^5
n⩽105
这是一道贪心题
维护当前匹配的R,G,B,RG,BG,RB,空的个数
然后加入一个字符时尽量加个数多的
例如,加入R,尽量加BG,不行就加B,G,再不行就空集
一个结论是:R,G,B不可能同时都有
RG,BG,RB不可能同时都有
加入时乘上对应的个数即可
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int Mod=998244353;
int n;
#define Maxn 300010
char str[Maxn];
int fact=1,Ans=1;
int a[7];//empty R G B RG BG RB
int main(){
scanf("%d",&n);
for(register int i=1;i<=n;++i)fact=1ll*fact*i%Mod;
scanf("%s",str+1);
for(register int i=1;i<=3*n;++i){
if(str[i]=='R'){
if(a[5]){
Ans=1ll*Ans*a[5]%Mod;
a[5]--;
continue;
}
if(a[2]){
Ans=1ll*Ans*a[2]%Mod;
a[2]--;
a[4]++;
continue;
}
if(a[3]){
Ans=1ll*Ans*a[3]%Mod;
a[3]--;
a[6]++;
continue;
}
a[1]++;
}else if(str[i]=='G'){
if(a[6]){
Ans=1ll*Ans*a[6]%Mod;
a[6]--;
continue;
}
if(a[1]){
Ans=1ll*Ans*a[1]%Mod;
a[1]--;
a[4]++;
continue;
}
if(a[3]){
Ans=1ll*Ans*a[3]%Mod;
a[3]--;
a[5]++;
continue;
}
a[2]++;
}else{
if(a[4]){
Ans=1ll*Ans*a[4]%Mod;
a[4]--;
continue;
}
if(a[1]){
Ans=1ll*Ans*a[1]%Mod;
a[1]--;
a[6]++;
continue;
}
if(a[2]){
Ans=1ll*Ans*a[2]%Mod;
a[2]--;
a[5]++;
continue;
}
a[3]++;
}
}
printf("%d\n",1ll*Ans*fact%Mod);
return 0;
}
T3:n个数,每次可以选第i个数,将其变成第i-1(这是循环序列),i,i+1个数的和
给定A,B,问A序列最少几步到达B。
n
≤
2
∗
1
0
5
,
1
⩽
A
i
,
B
i
⩽
1
0
9
n\leq 2*10^5,1\leqslant A_i,B_i\leqslant 10^9
n≤2∗105,1⩽Ai,Bi⩽109
反向考虑,然后每次从最大值考虑
剩下的就很好想了
O
(
n
l
o
g
2
n
l
o
g
2
V
)
O(nlog_2nlog_2V)
O(nlog2nlog2V)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
int n;
#define Maxn 200010
int a[Maxn],b[Maxn];
struct Data{
int id,val;
bool operator <(const Data &z)const{return val<z.val;}
};
priority_queue<Data> Q;
int main(){
scanf("%d",&n);
for(register int i=0;i<n;++i)scanf("%d",&b[i]);
for(register int i=0;i<n;++i){
scanf("%d",&a[i]);
if(a[i]<b[i]){
puts("-1");
return 0;
}
}
for(register int i=0;i<n;++i)
if(a[i]!=b[i])Q.push((Data){i,a[i]});
long long ans=0;
while(!Q.empty()){
int x=Q.top().id;
Q.pop();
int y1=(x-1+n)%n,y2=(x+1)%n;
int tmp=(a[x]-b[x])/(a[y1]+a[y2]);
ans+=tmp;
if(tmp==0&&a[x]!=b[x]){puts("-1");return 0;}
a[x]-=tmp*(a[y1]+a[y2]);
if(a[x]!=b[x])Q.push((Data){x,a[x]});
}
printf("%lld\n",ans);
return 0;
}
T4:这里不妨采用简化题意
给一个n*m的矩阵,n行每行是1~n的数构成
1~n的数在整个矩阵中各出现m次
给每行重排列,使得每一列是1~n的一个排列
考虑逐步确定每一列,即递归
如果现在是n行m’列
容易建出一个二分图
我们采用Hall定理得知它一定有完美匹配
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int inf=2147483647;
int n,m;
#define V 205
#define E 30010
int head[V],v[E],w[E],cap[E],nxt[E],cur[V],tot=0;
inline void add_edge(int s,int e,int t){
tot++;v[tot]=e;w[tot]=1;cap[tot]=t;nxt[tot]=head[s];head[s]=tot;
tot++;v[tot]=s;w[tot]=0;cap[tot]=t;nxt[tot]=head[e];head[e]=tot;
}
int a[V][V];
vector<int> g[V][V];
int res[V][V],tmp[V];
inline int col(int x){
if(x%m==0)return x/m;
return x/m+1;
}
int S,T;
int Q[V],hd,tl,d[V];
bool bfs(){
memset(d,-1,sizeof(int)*(2*n+3));
d[S]=0;
hd=tl=0;
Q[tl++]=S;
while(hd<tl){
int u=Q[hd];
hd++;
for(int i=head[u];i;i=nxt[i])
if(w[i]&&d[v[i]]==-1){
d[v[i]]=d[u]+1;
Q[tl++]=v[i];
if(v[i]==T)return true;
}
}
return false;
}
int dfs(int u,int flow){
if(u==T||!flow)return flow;
int ans=0,res;
for(int &i=head[u];i;i=nxt[i])
if(w[i]&&d[v[i]]==d[u]+1&&(res=dfs(v[i],min(flow,w[i])))){
w[i]-=res;
if(i&1)w[i+1]+=res;
else w[i-1]+=res;
ans+=res;
flow-=res;
if(!flow)break;
}
return ans;
}
inline void solve(int x){
S=2*n+1;T=2*n+2;
memset(head,0,sizeof(int)*(2*n+3));tot=0;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
if(g[i][j].size())add_edge(i,j+n,g[i][j][g[i][j].size()-1]);
for(register int i=1;i<=n;++i){
add_edge(S,i,0);
add_edge(i+n,T,0);
}
int haha=0;
memcpy(cur,head,sizeof(int)*(2*n+3));
while(bfs()){
haha+=dfs(S,inf);
memcpy(head,cur,sizeof(int)*(2*n+3));
}
int tmp=-1;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j){
if(g[i][j].size()){
tmp+=2;
if(w[tmp]==0){
res[i][x]=cap[tmp];
g[i][j].pop_back();
}
}
}
}
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
rd(n);rd(m);
for(register int i=1;i<=n;++i)
for(register int j=1;j<=m;++j){
rd(a[i][j]);
g[i][col(a[i][j])].push_back(a[i][j]);
}
for(register int i=1;i<=m;++i)solve(i);
for(register int i=1;i<=n;++i){
for(register int j=1;j<=m;++j)printf("%d ",res[i][j]);
puts("");
}
for(register int i=1;i<=m;++i){
for(register int j=1;j<=n;++j)tmp[j]=res[j][i];
sort(tmp+1,tmp+n+1);
for(register int j=1;j<=n;++j)res[j][i]=tmp[j];
}
for(register int i=1;i<=n;++i){
for(register int j=1;j<=m;++j)printf("%d ",res[i][j]);
puts("");
}
return 0;
}
T5:给出一个长度为n的串S,每次从SS’(即S的reverse)中选取一个长度为n的字串
操作K次,求字典序最小的结果
考虑最小字符a,尽量最大化前缀
假设最长连续的a为L,末尾的a有G个
那么最后a的前缀
m
a
x
(
L
∗
2
K
−
1
,
G
∗
2
K
)
max(L*2^{K-1},G*2^K)
max(L∗2K−1,G∗2K)
确定好第一步后,保证这样最后a的前缀最大化
复杂度
O
(
n
2
)
O(n^2)
O(n2)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,K;
#define Maxn 10010
char S[Maxn],Ans[Maxn];
int L=0,H;
int G=0;
char c='z';
char ch[Maxn];
int sum[Maxn];
inline void solve(){
for(register int i=1;i<=n-L;++i)ch[i]=ch[L-H+i];
for(register int i=n-L+1;i<=n;++i)ch[i]=c;
reverse(ch+1,ch+n+1);
}
int main(){
scanf("%d%d",&n,&K);
scanf("%s",S+1);
for(register int i=1;i<=n;++i)Ans[i]=c;
for(register int i=1;i<=n;++i)
if(S[i]<c)c=S[i];
int at;
bool flag=false;
for(register int i=1;i<=n;i=at)
if(S[i]==c){
at=i;
while(at<=n&&S[at]==c)at++;
if(at==n+1)G=at-i;
if(at-i>=L){
L=at-i;
if(at==n+1)flag=true;
}
}else at=i+1;
H=L;
if(G*2>H){
H=G;L=G;
flag=true;
}
if(!flag)K--;
for(register int i=1;i<=K;++i){
L*=2;
if(L>=n){
for(register int j=1;j<=n;++j)printf("%c",c);
return 0;
}
}
if(flag){
for(register int i=1;i<=n;++i)ch[i]=S[i];
solve();
bool Ha=false;
for(register int i=1;i<=n;++i){
if(Ha==false&&ch[i]>Ans[i])break;
if(ch[i]<Ans[i])Ha=true;
if(Ha)Ans[i]=ch[i];
}
}else{
for(register int i=n+1;i<=2*n;++i)S[i]=S[2*n+1-i];
sum[0]=0;
for(register int i=1;i<=2*n;++i){
sum[i]=sum[i-1];
if(S[i]==c)sum[i]++;
}
for(register int i=n;i<=2*n;++i)
if(sum[i]-sum[i-H]==H){
for(register int j=1;j<=n;++j)ch[j]=S[i-n+j];
solve();
bool Ha=false;
for(register int i=1;i<=n;++i){
if(Ha==false&&ch[i]>Ans[i])break;
if(ch[i]<Ans[i])Ha=true;
if(Ha)Ans[i]=ch[i];
}
}
}
for(register int i=1;i<=n;++i)printf("%c",Ans[i]);
return 0;
}
T6:突然想咕咕咕了…
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<vector>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,L;
#define Maxn 200010
ll Ans=0;
struct data{
int val,pos;
bool operator <(const data &z)const{return val==z.val?pos<z.pos:val<z.val;}
}seq[Maxn];
struct Data{
int l,r;
int x,y;
bool operator <(const Data &z)const{return l<z.l;}
};
vector<Data> A,B,vec2;
vector<pair<int,int> > vec1;
int num[Maxn];
inline ll calc(vector< pair<int,int> > &a){
ll res=0,sum=0;
for(int i=L-1,j=0;i<a.size();i++,j++){
sum+=a[j].first;
res+=a[i].second*sum;
}
return res;
}
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
rd(n);rd(L);
for(register int i=1;i<=n;++i){
rd(num[i]);
seq[i]=(data){num[i],i};
}
sort(seq+1,seq+n+1);
ll Ans=n;
int at=1,tmp;
while(true){
if(A.empty()){
if(at>n)break;
else tmp=seq[at].val;
}else tmp++;
while(tmp==seq[at].val)A.push_back((Data){seq[at].pos,seq[at].pos,1,1}),at++;
B.clear();sort(A.begin(),A.end());
for(int i=0,j;i<A.size();i=j+1){
j=i;
while(j+1<A.size()&&A[j+1].l==A[j].r+1)j++;
int len=j-i+1,cnt=len/L;
if(cnt){
vec1.clear();
vec2.clear();
for(register int k=i;k<=j;++k)vec1.push_back(make_pair(A[k].x,A[k].y));
Ans+=calc(vec1);
for(register int k=1;k<=cnt;++k)
vec2.push_back((Data){A[i].l+k-1,(k==cnt)?A[j].r:A[i].l+k-1,0,0});
for(register int k=i;k<=j;++k){
int tl=k-i+1,tr=j-k+1;
if(tl>=L)vec2[tl/L-1].y+=A[k].y;
if(tr>=L)vec2[cnt-tr/L].x+=A[k].x;
}
vec1.clear();
for(register int k=0;k<cnt;++k)vec1.push_back(make_pair(vec2[k].x,vec2[k].y));
Ans-=calc(vec1);
for(register int k=0;k<cnt;++k)B.push_back(vec2[k]);
}
}
A.clear();
for(int i=0;i<B.size();++i)A.push_back(B[i]);
}
printf("%lld\n",Ans);
return 0;
}