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
#include
#include
#include
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
#include
#include
#include
#include
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 Q;
int main(){
scanf("%d",&n);
for(register int i=0;i
T4:这里不妨采用简化题意
给一个n*m的矩阵,n行每行是1~n的数构成
1~n的数在整个矩阵中各出现m次
给每行重排列,使得每一列是1~n的一个排列
考虑逐步确定每一列,即递归
如果现在是n行m’列
容易建出一个二分图
我们采用Hall定理得知它一定有完美匹配
#include
#include
#include
#include
#include
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 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'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
#include
#include
#include
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]=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])break;
if(ch[i]
T6:突然想咕咕咕了…
#include
#include
#include
#include
#include
#include
#include
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 A,B,vec2;
vector > vec1;
int num[Maxn];
inline ll calc(vector< pair > &a){
ll res=0,sum=0;
for(int i=L-1,j=0;i'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=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