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 }
95pt

 

最后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 }
View Code

 

多项式

披着斗地主外皮的多项式??瑟瑟发抖。

模拟只给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 }
30pt

 

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 }
View Code

 

迷宫

线段树时空复杂度都怎么算怎么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 }
View Code

 

动态数点

从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 }
李巨做法的代码

 

posted @ 2018-10-05 19:38  啊宸  阅读(201)  评论(0编辑  收藏  举报