2018 Multi-University Training Contest 2
1003:Cover
巧妙的构造,先找出所有奇数点,再成对连边,在新图里面跑欧拉回路(dfs边到底),切开之前连的边就是划分方案,这样能得到答案是max(d/2,1) (d为奇数点的个数)
1 #include<cmath> 2 #include<queue> 3 #include<cctype> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<algorithm> 8 9 #define maxn 300000+5 10 11 using namespace std; 12 13 struct Edge{ 14 int u,v,nxt; 15 }e[maxn<<1]; 16 17 vector <int> ov,rec[maxn]; 18 19 int head[maxn],bv[maxn],be[maxn<<1],du[maxn]; 20 int n,m,ind,ans; 21 22 void addedge(int x,int y){ 23 e[ind]=(Edge){x,y,head[x]},head[x]=ind++; 24 e[ind]=(Edge){y,x,head[y]},head[y]=ind++; 25 } 26 27 void dfs1(int x){//找到所有的奇数点 28 bv[x]=1; 29 if(du[x]&1) ov.push_back(x); 30 for(int i=head[x];i!=-1;i=e[i].nxt) 31 if(!bv[e[i].v]){ 32 dfs1(e[i].v); 33 } 34 } 35 36 void dfs2(int x){ 37 for(int i=head[x];i!=-1;i=e[i].nxt) 38 if(!be[i]){ 39 be[i]=be[i^1]=1; 40 dfs2(e[i].v); 41 if(i>=2*m) ans++; 42 else{ 43 // printf("%d\n",i); 44 if(i&1) rec[ans].push_back(i/2+1); 45 else rec[ans].push_back(-(i/2+1)); 46 } 47 } 48 } 49 50 inline int in(){ 51 int x=0; char ch=getchar(); 52 for(;!isdigit(ch);ch=getchar()); 53 for(; isdigit(ch);ch=getchar()) x=x*10+ch-'0'; 54 return x; 55 } 56 57 int main(){ 58 freopen("1003.in","r",stdin); 59 freopen("1003.out","w",stdout); 60 while(~scanf("%d%d",&n,&m)){ 61 for(int i=1;i<=n;i++) head[i]=-1; 62 ind=ans=0; 63 for(int i=1;i<=m;i++){ 64 int x,y; 65 x=in(); y=in(); 66 addedge(x,y); du[x]++; du[y]++; 67 } 68 for(int i=1;i<=n;i++) 69 if(!bv[i] && du[i]){ 70 dfs1(i); 71 if(!ov.size()) ov.push_back(i); 72 for(int j=2;j<ov.size();j+=2) 73 addedge(ov[j],ov[j+1]); 74 ans++; 75 dfs2(ov[0]); 76 ov.clear(); 77 } 78 printf("%d\n",ans); 79 for(int i=1;i<=ans;i++){ 80 int t=rec[i].size(); 81 printf("%d",t); 82 for(int j=0;j<t;j++) 83 printf(" %d",rec[i][j]); 84 puts(""); 85 rec[i].clear(); 86 } 87 for(int i=0;i<=ind;i++) be[i]=0; 88 for(int i=1;i<=n;i++) du[i]=bv[i]=0; 89 } 90 return 0; 91 }
1004:Game
结论题,输出yes就好了
1005:Hack It
不知名的构造,难受,不会证明,但n=p^2的矩形里边最多能放p^3个1
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> #define LSON l,m,x<<1 #define RSON m+1,r,x<<1|1 using namespace std; const int MAX=3000+5; int p=47; char mp[MAX][MAX]; int main(){ int i,j,k; int len=p*p; for(i=1;i<=len;i++){ for(j=1;j<=len;j+=p){ mp[i][j+(j/p*i+(i-1)/p)%p]=1; } } puts("2000"); for(i=1;i<=2000;i++){ for(j=1;j<=2000;j++) printf("%d",mp[i][j]); putchar('\n'); } return 0; }
1006:Matrix
解法一:
这个解法也被卡常,用long long运算太慢。得像标称那样用int运算。
解法二:dls直播讲的,比题解直观
ans=∑∑C(n,i)C(m,j)F[n-i][m-j],F[n-i][m-j]表示选出i行j列后剩下的行和列都不完全填满的方案数,然后F这个东西是可以通过容斥求出来的
F[a][b]=∑∑C(a,i)C(b,j)(-1)^(i+j)*2^((a-i)*(b-j))然后预处理这个F就可以,然后为了优化常数,公式暴力展开,一堆消消消,就行了
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> using namespace std; const int mod=998244353; int c[3010][3010],mi[9000010],f[3010][3010],sum_row[3010],sum_col[3010]; int main() { int i,j; c[0][0]=1; for(i=1;i<=3000;i++) { c[i][0]=1; c[i][i]=1; for(j=1;j<i;j++) { c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod; } } mi[0]=1; for(i=1;i<=9000000;i++) mi[i]=(mi[i-1]<<1)%mod; int n,m,A,B; while(scanf("%d%d%d%d",&n,&m,&A,&B)!=EOF) { sum_row[A]=1; sum_col[B]=1; for(i=A+1;i<=n;i++) { sum_row[i]=1; for(j=A;j<i;j++) { sum_row[i]=((sum_row[i]-(long long)sum_row[j]*c[i][j]))%mod; } //cout<<sum_row[i]<<endl; } for(i=B+1;i<=m;i++) { sum_col[i]=1; for(j=B;j<i;j++) { sum_col[i]=((sum_col[i]-(long long)sum_col[j]*c[i][j]))%mod; } } for(i=A;i<=n;i++) { for(j=B;j<=m;j++) { f[i][j]=(long long)c[n][i]*c[m][j]%mod*mi[(n-i)*(m-j)]%mod; } } long long ans=0; for(i=A;i<=n;i++) { for(j=B;j<=m;j++) { ans=(ans+(long long)f[i][j]*sum_col[j]%mod*sum_row[i]%mod)%mod; } } ans=(ans+mod)%mod; printf("%lld\n",ans); } return 0; }
1007:Naive Operations
把向下取整转化为当a数组到达b数组的限制时产生1的贡献。故把a数组+1转换为b数组-1,当减到0时产生1贡献并修改为原值。可用线段树维护最小值和-1标记,得到0时暴力修改回原值,由于是1~n的排列故保证修改复杂度均摊为logn
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<algorithm> 5 6 #define maxn 100000+5 7 8 using namespace std; 9 10 typedef long long LL; 11 12 struct Seg_Tree{ 13 int l,r; 14 int mi,tag,ans; 15 }tr[maxn<<2]; 16 17 int b[maxn]; 18 int n,q; 19 20 void Update(int k){ 21 tr[k].mi=min(tr[k<<1].mi,tr[k<<1|1].mi); 22 tr[k].ans=tr[k<<1].ans+tr[k<<1|1].ans; 23 } 24 25 void Pushdown(int k){ 26 if(tr[k].tag){ 27 tr[k<<1].tag+=tr[k].tag; tr[k<<1|1].tag+=tr[k].tag; 28 tr[k<<1].mi-=tr[k].tag; tr[k<<1|1].mi-=tr[k].tag; 29 tr[k].tag=0; 30 } 31 } 32 33 void Build(int k,int l,int r){ 34 tr[k].l=l; tr[k].r=r; tr[k].tag=tr[k].ans=0; 35 if(l==r){ 36 tr[k].mi=b[l]; 37 return; 38 } 39 int mid=(l+r)>>1; 40 Build(k<<1,l,mid); 41 Build(k<<1|1,mid+1,r); 42 Update(k); 43 } 44 45 void Modify(int k,int l,int r,int val){ 46 Pushdown(k); 47 if(tr[k].l==l && tr[k].r==r){ 48 tr[k].tag+=val; tr[k].mi-=val; 49 return; 50 } 51 if(tr[k<<1].r>=r) Modify(k<<1,l,r,val); 52 else if(tr[k<<1|1].l<=l) Modify(k<<1|1,l,r,val); 53 else Modify(k<<1,l,tr[k<<1].r,val),Modify(k<<1|1,tr[k<<1|1].l,r,val); 54 Update(k); 55 } 56 57 int Query(int k,int l,int r){ 58 Pushdown(k); 59 if(tr[k].l==l && tr[k].r==r) return tr[k].ans; 60 if(tr[k<<1].r>=r) return Query(k<<1,l,r); 61 else if(tr[k<<1|1].l<=l) return Query(k<<1|1,l,r); 62 else return Query(k<<1,l,tr[k<<1].r)+Query(k<<1|1,tr[k<<1|1].l,r); 63 } 64 65 void Check(int k,int l,int r){ 66 if(tr[k].l==tr[k].r){ 67 tr[k].ans++; tr[k].mi=b[l]; 68 return; 69 } 70 Pushdown(k); 71 if(tr[k].mi==0){ 72 if(tr[k<<1].mi==0) Check(k<<1,l,tr[k<<1].r); 73 if(tr[k<<1|1].mi==0) Check(k<<1|1,tr[k<<1|1].l,r); 74 } 75 Update(k); 76 } 77 78 int main(){ 79 while(~scanf("%d%d",&n,&q)){ 80 for(int i=1;i<=n;i++) 81 scanf("%d",&b[i]); 82 Build(1,1,n); 83 char op[10]; 84 for(int i=1;i<=q;i++){ 85 int l,r; 86 scanf("%s%d%d",op,&l,&r); 87 if(op[0]=='a'){ 88 Modify(1,l,r,1); 89 Check(1,l,r); 90 } 91 else 92 printf("%d\n",Query(1,l,r)); 93 } 94 } 95 return 0; 96 }
1010:Swaps and Inversions
考虑从最小的且最靠前的元素开始往前移,每次移动一定会减少一个逆序对,设逆序对数为t,故答案为t*min(x,y)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 6 #define maxn 100000+5 7 8 using namespace std; 9 10 int a[maxn],c[maxn],p[maxn]; 11 long long bit[maxn]; 12 int n,x,y,tot,cnt; 13 14 int search(int x){ 15 int l=1,r=cnt,ans; 16 while(l<=r){ 17 int mid=(l+r)>>1; 18 if(c[mid]<x) l=mid+1; 19 else r=mid-1,ans=mid; 20 } 21 return ans; 22 } 23 24 void add(int x){ 25 while(x<maxn){ 26 bit[x]++; 27 x+=x&-x; 28 } 29 } 30 31 long long sum(int x){ 32 long long res=0; 33 while(x){ 34 res+=bit[x]; 35 x-=x&-x; 36 } 37 return res; 38 } 39 40 int main(){ 41 while(~scanf("%d%d%d",&n,&x,&y)){ 42 memset(bit,0,sizeof(bit)); 43 memset(a,0,sizeof(a)); 44 memset(p,0,sizeof(p)); 45 memset(c,0,sizeof(c)); 46 int flag=0; cnt=tot=0; 47 for(int i=1;i<=n;i++) 48 scanf("%d",&a[i]),c[i]=a[i]; 49 if(x>y) flag=1; 50 else flag=0; 51 sort(c+1,c+1+n); 52 c[0]=0x3f3f3f3f; 53 for(int i=1;i<=n;i++) 54 if(c[i]!=c[i-1]) c[++cnt]=c[i]; 55 for(int i=1;i<=n;i++) 56 p[i]=search(a[i]); 57 long long ans=0; 58 for(int i=n;i>=1;i--){ 59 long long tmp=sum(p[i]-1); 60 ans+=tmp; add(p[i]); 61 } 62 if(flag) printf("%lld\n",ans*y); 63 else printf("%lld\n",ans*x); 64 } 65 66 return 0; 67 }