NOIp2018集训test-10-4/test-10-5 (联考四day1/day2)
这个day1稍微有点毒瘤吧??
DAY1
排列
以前总是把day1t1想太复杂了翻车,差不多往正解的方向想了一下感觉不可能这么复杂这可是noipday1t1啊一定有非常简单的方法然后翻车了??
题目转换为求二分图完全匹配数,这个怎么都是十分不好算的,容易想到容斥。
用g[i]表示起码选了i条二分图的补图中的边的匹配数。
那么答案就是
$ans=\sum_{i=0}^{n}g[i]*(n-i)!*(-1)^i$
发现这个二分图的补图长得十分有特点啊。
这是若干条不想交的链构成的图,链与链之间互不影响可以单独考虑。用f[i][j][0/1]表示选到某条链上第i个点,在这条链上选了j条边,第i个点有没有被选的方案数,可以分别dp出每条链。
再跑个背包合并所有链,容斥统计答案即可。这样就有95分啦。
1 //Achen
2 #include<bits/stdc++.h>
3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
5 #define Formylove return 0
6 const int N=2007,p=998244353;
7 using namespace std;
8 typedef long long LL;
9 typedef double db;
10 int n,K,g[N],f[N][N][2],fac[N],up;
11
12 template<typename T>void read(T &x) {
13 T f=1; x=0; char ch=getchar();
14 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
15 if(ch=='-') f=-1,ch=getchar();
16 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
17 }
18
19 int mo(LL x) { return x%p; }
20
21 #define ANS
22 int main() {
23 #ifdef ANS
24 freopen("permutation.in","r",stdin);
25 freopen("permutation.out","w",stdout);
26 #endif
27 read(n); read(K);
28 fac[0]=1;
29 For(i,1,n) fac[i]=(LL)fac[i-1]*i%p;
30 g[0]=1;
31 For(cs,1,2) {
32 For(i,1,K) {
33 f[i][0][0]=1;
34 int j=i,tp=0;
35 for(;;) {
36 if(j+K>n) break;
37 j+=K; tp++;
38 For(l,0,tp) {
39 f[j][l+1][1]=f[j-K][l][0];
40 f[j][l][0]=(f[j-K][l][0]+f[j-K][l][1])%p;
41 }
42 }
43 Rep(l,up,0) For(m,1,tp)
44 (g[l+m]+=(LL)g[l]*(f[j][m][0]+f[j][m][1])%p)%=p;
45 up+=tp;
46 }
47 }
48 LL ans=0;
49 For(i,0,n) {
50 //printf("%d\n",g[i]);
51 if(!(i&1)) ans=(ans+(LL)g[i]*fac[n-i]%p)%p;
52 else ans=(ans-(LL)g[i]*fac[n-i]%p+p)%p;
53 }
54 printf("%lld\n",ans);
55 //cerr<<clock()<<endl;
56 Formylove;
57 }
最后5分是什么玩意???
发现这些链其实都一样,只有两种不同长度。又发现刚才的dp其实是一个组合数。就可以直接得到最后要的f,然后多项式exp就可以的答案了。noip之前我不会写这种玩意的。。
苹果树
最简单的一道题,很多人都切了,而且各种方法花样AC。大致有标解的lca,辉神李巨的树剖,ljq的伪tarjan。但是我的随机化应该是最好写的,写得快点大概5min就够了吧。
1 //Achen
2 #include<bits/stdc++.h>
3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
5 #define Formylove return 0
6 const int N=600007;
7 using namespace std;
8 typedef unsigned long long LL;
9 typedef double db;
10 int n,m;
11
12 template<typename T>void read(T &x) {
13 T f=1; x=0; char ch=getchar();
14 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
15 if(ch=='-') f=-1,ch=getchar();
16 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
17 }
18
19 int ecnt,fir[N],nxt[N<<1],to[N<<1];
20 void add(int u,int v) {
21 nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
22 nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
23 }
24
25 map<LL,int>mp,mp2;
26 LL val[N],val2[N],ans;
27 void dfs(int x,int fa) {
28 for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
29 dfs(to[i],x);
30 val[x]=(val[x]^val[to[i]]);
31 }
32 if(fa) {
33 if(!val[x])
34 ans+=m;
35 else if(mp[val[x]])
36 ans++;
37 }
38 }
39
40 #define ANS
41 int main() {
42 #ifdef ANS
43 freopen("tree.in","r",stdin);
44 freopen("tree.out","w",stdout);
45 #endif
46 srand(998244353);
47 read(n); read(m);
48 For(i,2,n) {
49 int u,v;
50 read(u); read(v);
51 add(u,v);
52 }
53 For(i,1,m) {
54 int u,v;
55 read(u); read(v);
56 LL t;
57 t=(((LL)rand()<<29)|rand());
58 while(!t) {
59 t=(((LL)rand()<<29)|rand());
60 }
61 mp[t]=1;
62 val[u]^=t;
63 val[v]^=t;
64 }
65 dfs(1,0);
66 printf("%llu\n",ans);
67 //cerr<<clock()<<endl;
68 Formylove;
69 }
多项式
披着斗地主外皮的多项式??瑟瑟发抖。
模拟只给50,我大概写模拟都要写3h+把。。。写了个30分的暴力还写挂了,没把不同花色的同种对子区分开。。。
还是noip之前不改系列。
1 //Achen
2 #include<bits/stdc++.h>
3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
5 #define Formylove return 0
6 const int N=50,p=998244353;
7 using namespace std;
8 typedef long long LL;
9 typedef double db;
10 int T,n,cnt[N],cc[N],C[25][25],pr[21];
11 LL ans;
12 char s[N];
13
14 template<typename T>void read(T &x) {
15 T f=1; x=0; char ch=getchar();
16 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
17 if(ch=='-') f=-1,ch=getchar();
18 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
19 }
20
21 void solve1() {
22 ans=0;
23 For(i,1,4) cc[i]=0;
24 For(i,3,16) cc[cnt[i]]++;
25 if(n==1) ans=1;
26 else if(n==2) {
27 if(cc[2]==1) ans=2;
28 else ans=1;
29 }
30 else if(n==3) {
31 if(cc[3]==1) ans=4;
32 else if(cc[2]==1) ans=2;
33 else ans=1;
34 }
35 else if(n==4) {
36 ans++; //4 single
37 if(cc[4]==1) ans+=14; //4:1 3+1:C(4,3) 2+2:3 2+1+1:C(4,2)
38 if(cc[3]==1) ans+=5; //3+1 3+1 2+1+1:C(3,2)
39 if(cc[2]==1) ans++; //2+1
40 else if(cc[2]==2) ans+=3; //2+2 2+1+1 2+1+1
41 }
42 }
43
44 void dfs2(int pos,int num,int lim) {
45 if(pos==17) {
46 ans=(ans+num)%p;
47 return;
48 }
49 //if(cnt[pos]==2) dfs2(pos+1,num*2%p,0); // 1+1 or 2
50 //else dfs2(pos+1,num,0); // 1
51 if(cnt[pos]==0) dfs2(pos+1,num,0);
52
53 for(int j=pos+1;cnt[j]&&j<=14;j++) { //shun zi
54 if(j>=pos+4&&j>lim) {
55 int N=num;
56 For(k,pos,j) {
57 N=(LL)N*C[cnt[k]][1]%p;
58 cnt[k]--;
59 }
60 dfs2(pos,N,j);
61 For(k,pos,j) cnt[k]++;
62 }
63 }
64 for(int j=pos;cnt[j]==2&&j<=14;j++) { //lian dui
65 if(j>=pos+2) {
66 dfs2(j+1,num,0);
67 }
68 }
69 }
70
71 #define ANS
72 int main() {
73 #ifdef ANS
74 freopen("polynomial.in","r",stdin);
75 //freopen("polynomial.out","w",stdout);
76 #endif
77 read(T);
78 For(i,0,20) C[i][0]=1;
79 pr[0]=1;
80 For(i,1,20) pr[i]=pr[i-1]*2%p;
81 For(i,1,20) For(j,1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%p;
82 while(T--) {
83 read(n);
84 memset(cnt,0,sizeof(cnt));
85 For(i,1,n) {
86 scanf("%s",s);
87 int len=strlen(s);
88 if(len==1) {
89 if(s[0]=='J') cnt[11]++;
90 else if(s[0]=='Q') cnt[12]++;
91 else if(s[0]=='K') cnt[13]++;
92 else if(s[0]=='A') cnt[14]++;
93 else {
94 if(s[0]-'0'==2) cnt[15]++;
95 else cnt[s[0]-'0']++;
96 }
97 }
98 else {
99 if(s[1]=='0') cnt[10]++;
100 else cnt[16]++;
101 }
102 }
103 For(i,1,n) scanf("%s",s);
104 ans=0;
105 if(n<=4) solve1();
106 else dfs2(3,1,0);
107 printf("%lld\n",ans);
108 }
109 //cerr<<clock()<<endl;
110 Formylove;
111 }
DAY2
day2其实并不难,应该是容易AK的,但是DCOI实在太菜了。。
我写t2的时候把线段树的时空复杂度算错了,就想写分块水水,码力太弱(本质是没想清楚),花了太多时间最终却没调出来,只交了暴力,还导致本来很简单的t3根本没时间思考,写了暴力就交。
序列
这种玩意套路的做法就是枚举每个起点i,然后分别统计后面a[j]-(j-i+1)大于0的和小于0的和,前面类似。
也就是每个位置的权值是a[i]-i,每次查询大于或小于某个权值的数的权值和。
树状数组肯定是可以做的,常数优秀一点说不定能过呢。
发现起点一位一位的移时,每次查询的那个数是一点点增大或减小的,而ai又很小,拿cnt数组记一下,每次把刚刚越过线的部分算一算就可以On做了。
1 //Achen
2 #include<bits/stdc++.h>
3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
5 #define Formylove return 0
6 const int N=4e6+7;
7 typedef long long LL;
8 typedef double db;
9 using namespace std;
10 LL n,a[N],cnt[N],pos;
11 LL ans[N],now,sum,sumcnt,nowcnt;
12
13 template<typename T>void read(T &x) {
14 char ch=getchar(); T f=1; x=0;
15 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
16 if(ch=='-') f=-1,ch=getchar();
17 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
18 }
19
20 #define ANS
21 int main() {
22 #ifdef ANS
23 freopen("a.in","r",stdin);
24 freopen("a.out","w",stdout);
25 #endif
26 read(n);
27 For(i,1,n) read(a[i]);
28 Rep(i,n,1) {
29 pos=1-i;
30 sum+=a[i]-i; sumcnt++;
31
32 if(a[i]-i>=pos) now+=a[i]-i,nowcnt++;
33
34 ans[i]=(now-nowcnt*pos)+((sumcnt-nowcnt)*pos-(sum-now));
35
36 cnt[a[i]-i+n]++;
37
38 now-=pos*cnt[pos+n];
39 nowcnt-=cnt[pos+n];
40 }
41
42 sum=now=sumcnt=nowcnt=0;
43 memset(cnt,0,sizeof(cnt));
44 For(i,1,n) {
45 pos=n-i;
46 sum+=a[i]-i; sumcnt++;
47 if(a[i]-i<=pos) now+=a[i]-i,nowcnt++;
48
49 ans[i+1]+=(nowcnt*pos-now)+((sum-now)-(sumcnt-nowcnt)*pos);
50
51 cnt[a[i]-i+n]++;
52
53 now-=pos*cnt[pos+n];
54 nowcnt-=cnt[pos+n];
55 }
56
57 LL rs=ans[1];
58 For(i,1,n) rs=min(rs,ans[i]);
59 printf("%lld\n",rs);
60 Formylove;
61 }
迷宫
线段树时空复杂度都怎么算怎么ok啊,而且超级好写的啊。。
就是有点卡常,我要加register才能卡过最后两个点。
1 //Achen
2 #include<bits/stdc++.h>
3 #define For(i,a,b) for(register int i=(a);i<=(b);i++)
4 #define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
5 #define Formylove return 0
6 #define inf 1e8
7 const int N=200007;
8 typedef long long LL;
9 typedef double db;
10 using namespace std;
11 int n,m,q,a[7][N];
12
13 template<typename T>void read(T &x) {
14 char ch=getchar(); T f=1; x=0;
15 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
16 if(ch=='-') f=-1,ch=getchar();
17 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
18 }
19
20 void GM(int &x,int y) { if(x>y) x=y; }
21
22 #define lc x<<1
23 #define rc ((x<<1)|1)
24 #define mid ((l+r)>>1)
25 int sg[N<<2][6][6];
26 void upd(int x,int l,int r) {
27 memset(sg[x],127/3,sizeof(sg[x]));
28 if(l==r) {
29 For(i,1,n) if(a[i][l]) sg[x][i][i]=0;
30 For(i,1,n) Rep(j,i-1,1) if(a[i][l]&&a[i-1][l]) {
31 GM(sg[x][i][j],sg[x][i-1][j]+1);
32 GM(sg[x][j][i],sg[x][i-1][j]+1);
33 }
34 }
35 else {
36 For(i,1,n) For(j,1,n) {
37 For(k,1,n) if(a[k][mid]&&a[k][mid+1])
38 GM(sg[x][i][j],sg[lc][i][k]+sg[rc][k][j]+1);
39 }
40 }
41 }
42
43 void build(int x,int l,int r) {
44 if(l==r) { upd(x,l,r); return; }
45 build(lc,l,mid); build(rc,mid+1,r);
46 upd(x,l,r);
47 }
48
49 void update(int x,int l,int r,int p1,int p2) {
50 if(l==r) {
51 a[p2][p1]^=1;
52 upd(x,l,r); return;
53 }
54 if(p1<=mid) update(lc,l,mid,p1,p2);
55 else update(rc,mid+1,r,p1,p2);
56 upd(x,l,r);
57 }
58
59 int tp[6][6],rs[6][6],ok;
60 void merge(int x,int l,int r) {
61 if(!ok) {
62 ok=1;
63 For(i,1,n) For(j,1,n)
64 tp[i][j]=sg[x][i][j];
65 }
66 else {
67 memset(rs,127/3,sizeof(rs));
68 For(i,1,n) For(j,1,n) {
69 For(k,1,n) if(a[k][l-1]&&a[k][l])
70 GM(rs[i][j],tp[i][k]+sg[x][k][j]+1);
71 }
72 memcpy(tp,rs,sizeof(rs));
73 }
74 }
75
76 void qry(int x,int l,int r,int ql,int qr) {
77 if(l>=ql&&r<=qr) { merge(x,l,r); return; }
78 if(ql<=mid) qry(lc,l,mid,ql,qr);
79 if(qr>mid) qry(rc,mid+1,r,ql,qr);
80 }
81
82 #define ANS
83 int main() {
84 #ifdef ANS
85 freopen("maze.in","r",stdin);
86 freopen("maze.out","w",stdout);
87 #endif
88 read(n); read(m); read(q);
89 For(i,1,n) For(j,1,m) read(a[i][j]);
90 build(1,1,m);
91 For(cs,1,q) {
92 int o,x,y,z,w;
93 read(o); read(x); read(y);
94 if(o==1)
95 update(1,1,m,y,x);
96 else {
97 read(z); read(w);
98 ok=0;
99 qry(1,1,m,y,w);
100 if(tp[x][z]>=inf) puts("-1");
101 else printf("%d\n",tp[x][z]);
102 }
103 }
104 Formylove;
105 }
动态数点
从n^2暴力优化到标解蛮容易的,二分长度,st表处理gcd和min值。只是似乎又要卡常了。
看李巨一个排序的复杂度爆踩std。
按a从小到大排序,然后拓展。拓展过的点就不用再拓展了,发现每个点最多被拓展两边,左边一遍右边一遍(3 15 5)。
辉神就更强了,从左到右依次拓展但是每次拓展的中心是上一次拓展的右边界的下一个,这样最坏的情况下也只能卡成nlogv的,而实际远不到上限,跑得飞快。
1 //Achen
2 #include<bits/stdc++.h>
3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
5 #define Formylove return 0
6 const int N=500007;
7 typedef long long LL;
8 typedef double db;
9 using namespace std;
10 int n,b[N],vis[N],a[N];
11 int tot,ans;
12
13 template<typename T>void read(T &x) {
14 char ch=getchar(); T f=1; x=0;
15 while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
16 if(ch=='-') f=-1,ch=getchar();
17 for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
18 }
19
20 struct node {
21 int pos,a;
22 friend bool operator <(const node&A,const node&B) {
23 return A.a<B.a;
24 }
25 }p[N];
26
27 #define ANS
28 int main() {
29 #ifdef ANS
30 freopen("point.in","r",stdin);
31 freopen("point.out","w",stdout);
32 #endif
33 read(n);
34 For(i,1,n) {
35 read(a[i]);
36 p[i].a=a[i];
37 p[i].pos=i;
38 }
39 sort(p+1,p+n+1);
40 For(i,1,n) {
41 int l=p[i].pos,r=p[i].pos;
42 if(vis[l]) continue;
43 while(l>1&&a[l-1]>=p[i].a&&a[l-1]%p[i].a==0)
44 vis[--l]=1;
45 while(r<n&&a[r+1]>=p[i].a&&a[r+1]%p[i].a==0)
46 vis[++r]=1;
47 b[l]=r-l;
48 ans=max(ans,r-l);
49 }
50 For(i,1,n) tot+=(b[i]==ans);
51 printf("%d %d\n",tot,ans);
52 For(i,1,n) if(b[i]==ans) printf("%d ",i);
53 puts("");
54 Formylove;
55 }