2018.7.10模拟赛

又咸鱼了。
原因:
1:策略失误,死磕最后一道题,觉得非常可做,结果别的题只写了暴力,最后一道题是&*|集训队作业题Orz。。。。爆零gg
2:组合数学的操作很弱啊。。。做的题看似难度大,实际上只是用到的算法难,实际上思维难度并不大。一遇到包装起来的题就gg

T1:
正难则反
从后往前思考放珠子,最后一个珠子的最后一个只有一种放法,剩下的随意
倒数第二个珠子的最后一个要放在当前剩下的最后一个位置,剩下的随意放。。。。
最后得到递推式(无耻复制别人的 )

吸取ghostcai的经验:模意义下记得写逆元。。。。
考场上智障了。。。。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int mod=998244353,N=1e6+7;
typedef long long ll;
ll n,col[N],fac[N],sum,inv[N];
ll ksm(ll d,ll z) {
	ll res=1;
	while(z) {
		if(z&1) res*=d,res%=mod;
		d*=d;
		d%=mod;
		z>>=1;
	}
	return res;
}
ll C(ll n,ll m) {
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void getinv() {
	for(int i=sum-1; i; i--)
		inv[i]=inv[i+1]*(i+1)%mod;
}
int main() {
	freopen("qiang.in","r",stdin);
	freopen("qiang.out","w",stdout);
	cin>>n;
	for(int i=1; i<=n; i++) cin>>col[i],sum+=col[i];
	fac[1]=1;
	fac[0]=1;
	inv[0]=1;
	for(ll i=2; i<=sum; i++) fac[i]=fac[i-1]*i%mod;
	inv[sum]=ksm(fac[sum],mod-2);
	getinv();
	ll ans=1,qz=1;
	for(int i=n; i; i--) {
		ans*=C(sum-qz,col[i]-1);
		ans%=mod;
		qz+=col[i];
	}
	cout<<ans;
}

T2
思维很抽象,但是说实话可以想到。考场上迷糊了,而且对状压的裸写法也忘得差不多了。。。复习,复习。。。
就是建一个图,把两个可以相互转移的状态连一条边,求跑j条路的方法Orz...
强啊。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int n,mod;
int a[16][16],c[16][16],d[16][16];
int g[16][16];
void add(int x,int y) {
	g[x][y]=g[y][x]=1;
}
bool is(int x) {
	int cnt=0;
	for(int i=0; (1<<i)<=x; i++) {
		if((1<<i)&x) {
			cnt++;
		} else {
			if(cnt&1) return 0;
			cnt=0;
		}
	}
	return !(cnt&1);
}
void addedge(int now,int bf) {
	if(!(now&bf)&&is(now|bf)) add(now,bf);
}
int f[16][16];
void mul(int x[][16],int y[][16]) {
	memset(c,0,sizeof c);
	for(int k=0; k<16; k++) {
		for(int i=0; i<16; i++) {
			for(int j=0; j<16; j++) {
				c[i][j]+=x[i][j]*y[j][k]%mod;
				c[i][j]%=mod;
			}
		}
	}
}
void ksm() {

	memcpy(a,g,sizeof g);
	memcpy(d,g,sizeof g);
	while(n) {
		if(n&1) {
			memset(c,0,sizeof c);
			for(int k=0; k<16; k++) {
				for(int i=0; i<16; i++) {
					for(int j=0; j<16; j++) {
						c[i][j]+=a[i][k]*d[j][k]%mod;
						c[i][j]%=mod;
					}
				}
			}
			memcpy(a,c,sizeof a);
		}
		memset(c,0,sizeof c);
		for(int k=0; k<16; k++) {
				for(int i=0; i<16; i++) {
					for(int j=0; j<16; j++) {
						c[i][j]+=d[i][k]*d[j][k]%mod;
						c[i][j]%=mod;
					}
				}
			}
		memcpy(d,c,sizeof d);
		n>>=1;
	}
}
int main() {
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	for(int i=0; i<16; i++) {
		for(int j=0; j<16; j++) {
			addedge(i,j);
		}
	}
	while(~scanf("%d%d",&n,&mod)&&n&&mod) {
		n--;
		ksm();
		cout<<a[0][0]<<endl;
	}
}

T3
据说某年集训队作业题。强啊。。。考场上推了半天,自以为推了正解,结果gg。。。Orz
我想的是一个毒瘤DP,枚举每个数到达需要的更改次数,通过前一个的推出来,结果考场上手玩错一个例子,以为自己写的对的。。。
正解:差分,贪心。
zhoutb:如果不是在mod 4意义下大家都会做吧!
大家:会!
我:瑟瑟发抖

不在mod 4意义下:差分一下,答案为所有正数之和。画成一个柱状图感受下。
在mod 4意义下:差分一下,抽象为可以给某个区间开头加4,末尾减4,最小化正数和。
so,做一个桶维护前面的负数出现的情况,枚举3~1,如果发现有前面的\(-j+4\)比加上现在正的\(c[i]\)更优,那么就改。
其实想一想就是非常难想,也不是看不懂。脑洞不够大啊。。。而且前面的基础就不太清楚啊。。。更别提联想到了

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1e6+10;
int n,a[N],b[N],s[8],T,c[N];
int main() {
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	scanf("%d",&T);
	while(T--) {
		int ans=0;
		memset(s,0,sizeof s);
		scanf("%d",&n);
		for(int i=1; i<=n; i++) scanf("%d",&a[i]);
		for(int i=1; i<=n; i++) scanf("%d",&b[i]);
		for(int i=1; i<=n; i++) a[i]=(b[i]+4-a[i])%4;
		for(int i=1; i<=n; i++) c[i]=a[i]-a[i-1];
		for(int i=1; i<=n; i++) {
			if(c[i]<=0) s[-c[i]]++;
			else {
				if(c[i]==2||c[i]==3) {
					for(int j=3; j; j--) {
						if(s[j]&&-4+j<c[i]) {
							ans+=4-j;
							s[j]--;
							c[i]=c[i]-4;
							s[-c[i]]++;
							break;
						}
					}
				}
				if(c[i]>0) ans+=c[i];
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

我是咸鱼,没人比我更鱼!

posted @ 2018-07-10 16:22  SWHsz  阅读(153)  评论(0编辑  收藏  举报