AtCoder Grand Contest 037 题解

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 n105
这是一道贪心题
维护当前匹配的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 n2105,1Ai,Bi109
反向考虑,然后每次从最大值考虑
剩下的就很好想了
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(L2K1,G2K)
确定好第一步后,保证这样最后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

你可能感兴趣的:(日常习题)