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

 

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

 

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

 

 

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

 

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

 

posted @ 2018-07-26 20:45  Hetui  阅读(183)  评论(0编辑  收藏  举报