10.9
A.
想到组合数……然后就没搞出来……
正解只差一步:容斥原理……
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=(int)1e7+5,mod=998244353; 7 int n,m,k; 8 long long po[maxn]; 9 long long qpow(long long x,int tim) 10 { 11 long long tmp=1; 12 for(;tim;tim>>=1,x=x*x%mod) 13 if(tim&1)tmp=tmp*x%mod; 14 return tmp; 15 } 16 long long inv[maxn]; 17 long long C(int n,int m) 18 { 19 inv[m]=inv[m]!=0?inv[m]:qpow(po[m],mod-2),inv[n-m]=inv[n-m]!=0?inv[n-m]:qpow(po[n-m],mod-2); 20 return po[n]*inv[m]%mod*inv[n-m]%mod; 21 } 22 int haha() 23 { 24 po[0]=1;for(int i=1;i<=(int)1e7;i++)po[i]=po[i-1]*i%mod; 25 scanf("%d%d%d",&n,&m,&k); 26 if(n>m||1ll*n*k<1ll*m){puts("0");return 0;} 27 long long ans=0;int sgn=1; 28 for(int i=0;i<=n&&m-i*k-1>=n-1;i++)ans=(ans+sgn*C(n,i)*C(m-i*k-1,n-1)%mod+mod)%mod,sgn=-sgn; 29 printf("%lld\n",ans); 30 } 31 int sb=haha(); 32 int main(){;}
B.
拓扑排序直接水过……
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=(int)1e6+5; 7 struct node 8 { 9 int from,to,next; 10 }edge[maxn<<1]; 11 int head[maxn],tot; 12 void addedge(int u,int v) 13 { 14 edge[++tot]=(node){u,v,head[u]};head[u]=tot; 15 } 16 #include <stack> 17 #include <queue> 18 int belong[maxn],size[maxn],cnt,scnt,dfn[maxn],low[maxn],n,m; 19 stack<int>s; 20 void dfs(int root) 21 { 22 dfn[root]=low[root]=++cnt;s.push(root); 23 for(int i=head[root];i;i=edge[i].next) 24 { 25 int v=edge[i].to; 26 if(!dfn[v])dfs(v),low[root]=min(low[root],low[v]); 27 else if(!belong[v])low[root]=min(low[root],dfn[v]); 28 } 29 if(low[root]==dfn[root]) 30 { 31 int k;scnt++; 32 do 33 { 34 k=s.top();s.pop(); 35 size[scnt]++;belong[k]=scnt; 36 }while(k!=root); 37 } 38 } 39 int dis[maxn],degree[maxn]; 40 queue<int>q; 41 int haha() 42 { 43 scanf("%d%d",&n,&m); 44 for(int i=1;i<=m;i++) 45 { 46 int x,y;scanf("%d%d",&x,&y); 47 addedge(x,y); 48 } 49 for(int i=1;i<=n;i++) 50 if(!dfn[i])dfs(i); 51 memset(head,0,sizeof(head)); 52 for(int i=1;i<=m;i++) 53 { 54 int u=edge[i].from,v=edge[i].to; 55 if(belong[u]!=belong[v])addedge(belong[u],belong[v]),degree[belong[v]]++; 56 } 57 int ans=0; 58 for(int i=1;i<=scnt;i++) 59 if(!degree[i])dis[i]=size[i],q.push(i),ans=max(ans,dis[i]); 60 while(!q.empty()) 61 { 62 int now=q.front();q.pop(); 63 for(int i=head[now];i;i=edge[i].next) 64 { 65 int v=edge[i].to;degree[v]--;dis[v]=max(dis[v],dis[now]+size[v]); 66 if(!degree[v])ans=max(ans,dis[v]),q.push(v); 67 } 68 } 69 printf("%d\n",ans); 70 } 71 int sb=haha(); 72 int main(){;}
C.
不可做啊……至今没人过……
10.10
A.
妈的智障……瞎模拟一分没有……完全没注意到超过17一定可以实现……然后就可以大大减少枚举量……
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=1000005; 4 int n,a[18*maxn],b[18*maxn],f[18*maxn],A[maxn],B[maxn],id[maxn]; 5 inline bool cmp(const int &x,const int &y) 6 { 7 return B[x]<B[y]; 8 } 9 int haha() 10 { 11 long long m;scanf("%d%lld",&n,&m); 12 int ans=0; 13 for(int i=1;i<=n;i++)scanf("%d%d",&A[i],&B[i]),id[i]=i; 14 sort(id+1,id+n+1,cmp); 15 for(int i=1;i<=n;i++) 16 { 17 if(B[id[i]]-B[id[i-1]]>17)b[i]=b[i-1]+18;else b[i]=b[i-1]+B[id[i]]-B[id[i-1]]; 18 a[b[i]]+=A[id[i]]; 19 } 20 for(int i=1;i<=b[n];i++) 21 { 22 if(i==1||i==2||i==3||i==5||i==6||i==9||i==10||i==13||i==17)continue; 23 f[i]=a[i]; 24 if(i>=7)f[i]+=max(f[i-4],f[i-7]); 25 else if(i>=4)f[i]+=f[i-4]; 26 ans=max(ans,f[i]); 27 } 28 printf("%d\n",ans); 29 } 30 int sb=haha(); 31 int main(){;}
B.
想过多种策略……然而当时一一否决,包括正解……最后发现其实根本不需要考虑路径长度和是否真的是那个值……因为最终一定合法值最小……
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=35; 4 int f[maxn][maxn][1775],a[maxn][maxn]; 5 int haha() 6 { 7 int t;scanf("%d",&t); 8 while(t--) 9 { 10 int n,m;scanf("%d%d",&n,&m); 11 for(int i=1;i<=n;i++) 12 for(int j=1;j<=m;j++)scanf("%d",&a[i][j]); 13 memset(f,0x3f,sizeof(f));f[1][1][a[1][1]]=a[1][1]*a[1][1]; 14 for(int i=1;i<=n;i++) 15 for(int j=1;j<=m;j++) 16 for(int k=0;k<=1770-a[i][j];k++) 17 { 18 f[i+1][j][k+a[i+1][j]]=min(f[i+1][j][k+a[i+1][j]],f[i][j][k]+a[i+1][j]*a[i+1][j]); 19 f[i][j+1][k+a[i][j+1]]=min(f[i][j+1][k+a[i][j+1]],f[i][j][k]+a[i][j+1]*a[i][j+1]); 20 } 21 int ans=0x7f7f7f7f; 22 for(int sum=1;sum<=1770;sum++) 23 { 24 if(f[n][m][sum]==0x3f3f3f3f)continue; 25 ans=min(ans,(n+m-1)*f[n][m][sum]-sum*sum); 26 } 27 printf("%d\n",ans); 28 } 29 } 30 int sb=haha(); 31 int main(){;}
C.
树归写挂……一份没有……
最后发现最后四个二进制位记录个数就过了的我眼泪掉下来……
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=100005; 4 struct node 5 { 6 int from,to,dis,next; 7 }edge[maxn<<1]; 8 int head[maxn],tot; 9 void addedge(int u,int v,int w) 10 { 11 edge[++tot]=(node){u,v,w,head[u]};head[u]=tot; 12 } 13 int n,m; 14 int W[20]; 15 int dis[maxn],size[maxn],Q[maxn][20],delta[maxn],sonnum[maxn][20],f[maxn]; 16 void dfs1(int root,int fa) 17 { 18 size[root]=1; 19 for(int i=head[root];i;i=edge[i].next) 20 { 21 int v=edge[i].to;int tmp=0; 22 if(v!=fa) 23 { 24 dfs1(v,root); 25 size[root]+=size[v];dis[root]+=dis[v]; 26 for(int j=0;j<16;j++)Q[root][j+edge[i].dis&15]+=Q[v][j],sonnum[v][j+edge[i].dis&15]+=Q[v][j],tmp+=W[j]*Q[v][j]; 27 Q[root][edge[i].dis&15]++,sonnum[v][edge[i].dis&15]++; 28 f[root]+=f[v]-tmp+size[v]*edge[i].dis; 29 } 30 } 31 for(int i=0;i<16;i++)delta[root]+=W[i]*Q[root][i]; 32 f[root]+=delta[root]; 33 } 34 int g[maxn],P[maxn][20]; 35 void dfs2(int root,int fa) 36 { 37 for(int i=head[root];i;i=edge[i].next) 38 { 39 int v=edge[i].to; 40 if(v!=fa) 41 { 42 int tmp=0,tmp2=0; 43 for(int j=0;j<16;j++) 44 { 45 tmp+=W[j]*Q[v][j]; 46 P[v][j+edge[i].dis&15]+=P[root][j]; 47 P[v][j+edge[i].dis&15]+=Q[root][j]-sonnum[v][j]; 48 tmp2+=W[j]*P[root][j]; 49 } 50 P[v][edge[i].dis&15]++; 51 int convey=f[root]-delta[root]-(f[v]-tmp+edge[i].dis*size[v]); 52 g[v]=convey+g[root]-tmp2+(n-size[v])*edge[i].dis; 53 for(int j=0;j<16;j++)g[v]+=P[v][j]*W[j]; 54 dfs2(v,root); 55 } 56 } 57 } 58 int haha() 59 { 60 scanf("%d%d",&n,&m); 61 for(int i=1;i<n;i++) 62 { 63 int x,y,z;scanf("%d%d%d",&x,&y,&z); 64 addedge(x,y,z);addedge(y,x,z); 65 } 66 for(int i=0;i<16;i++)W[i]=(i^m)-i; 67 dfs1(1,0);dfs2(1,0); 68 for(int i=1;i<=n;i++)printf("%d\n",f[i]+g[i]); 69 } 70 int sb=haha(); 71 int main(){;}
10.11 ——真·翻车
A.
没判重飞了70分……100->30
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=100005; 4 int a[maxn],f[maxn],n; 5 multiset<int>S; 6 int gcd(int a,int b){return !b?a:gcd(b,a%b);} 7 int haha() 8 { 9 scanf("%d",&n); 10 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 11 f[1]=1;S.insert(a[1]); 12 int gongcha=0; 13 for(int i=2;i<=n;i++) 14 { 15 if(S.count(a[i])){S.clear();gongcha=0;f[i]=f[i-1]+1;S.insert(a[i]);continue;} 16 S.insert(a[i]); 17 multiset<int>::iterator it=S.lower_bound(a[i]),it2=it,it3=it; 18 if(it!=S.begin())--it; 19 ++it2;if(it2==S.end())--it2; 20 if(it2==it3||it==it3) 21 { 22 gongcha=gcd(gongcha,(*it2)-(*it)); 23 if(gongcha<=1){S.clear();gongcha=0;S.insert(a[i]);f[i]=f[i-1]+1;continue;} 24 f[i]=f[i-1];continue; 25 } 26 int bigger=(*it2),smaller=(*it); 27 gongcha=gcd(gongcha,bigger-a[i]);gongcha=gcd(gongcha,a[i]-smaller); 28 if(gongcha<=1){S.clear();gongcha=0;S.insert(a[i]);f[i]=f[i-1]+1;continue;} 29 f[i]=f[i-1]; 30 } 31 printf("%d\n",f[n]); 32 } 33 int sb=haha(); 34 int main(){;}
B.
没考虑集合大小为1时要建双向边日飞100分……100->0
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=500005; 4 struct node 5 { 6 int from,to,next; 7 }edge[maxn]; 8 int head[maxn],tot; 9 void addedge(int u,int v) 10 { 11 edge[++tot]=(node){u,v,head[u]};head[u]=tot; 12 } 13 int n,m,num,tim,vis[maxn]; 14 int dfs(int now,int tar) 15 { 16 if(now==tar)return 1;vis[now]=tim; 17 for(int i=head[now];i;i=edge[i].next) 18 { 19 int v=edge[i].to; 20 if(vis[v]!=tim) 21 if(dfs(v,tar))return 1; 22 } 23 return 0; 24 } 25 int haha() 26 { 27 scanf("%d%d",&n,&m);num=n; 28 while(m--) 29 { 30 int opt;scanf("%d",&opt); 31 if(!opt) 32 { 33 num++;int dir,sum;scanf("%d%d",&dir,&sum); 34 for(int i=1;i<=sum;i++) 35 { 36 int x;scanf("%d",&x); 37 if(sum==1){addedge(num,x),addedge(x,num);break;} 38 if(!dir)addedge(num,x);else addedge(x,num); 39 } 40 } 41 else 42 { 43 tim++;int fr,to;scanf("%d%d",&fr,&to); 44 printf("%d\n",dfs(fr,to)); 45 } 46 } 47 } 48 int sb=haha(); 49 int main(){;}
C.
口胡了一个完全不对的单调队列结果操作完全错误炸飞50分……60->10
实际上这个东西根本不能用单调队列……因为可以构造出某些数据,f数组极小,B数组极大,结果在更新单调队列时直接被扔掉,但其实后面它还可能成为最优解……(不过这样数据很难造吧……对拍两千多组数据都没错……)
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=500005; 4 struct node 5 { 6 int from,to,next; 7 }edge[maxn]; 8 int head[maxn],tot; 9 void addedge(int u,int v) 10 { 11 edge[++tot]=(node){u,v,head[u]};head[u]=tot; 12 } 13 int n,m,num,tim,vis[maxn]; 14 int dfs(int now,int tar) 15 { 16 if(now==tar)return 1;vis[now]=tim; 17 for(int i=head[now];i;i=edge[i].next) 18 { 19 int v=edge[i].to; 20 if(vis[v]!=tim) 21 if(dfs(v,tar))return 1; 22 } 23 return 0; 24 } 25 int haha() 26 { 27 scanf("%d%d",&n,&m);num=n; 28 while(m--) 29 { 30 int opt;scanf("%d",&opt); 31 if(!opt) 32 { 33 num++;int dir,sum;scanf("%d%d",&dir,&sum); 34 for(int i=1;i<=sum;i++) 35 { 36 int x;scanf("%d",&x); 37 if(sum==1){addedge(num,x),addedge(x,num);break;} 38 if(!dir)addedge(num,x);else addedge(x,num); 39 } 40 } 41 else 42 { 43 tim++;int fr,to;scanf("%d%d",&fr,&to); 44 printf("%d\n",dfs(fr,to)); 45 } 46 } 47 } 48 int sb=haha(); 49 int main(){;}