又咸鱼了。
原因:
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
",ans);
}
return 0;
}