Comet OJ Contest #3
阿新 • • 發佈:2019-05-14
pan class == first out base nbsp return 註意
A:簽到。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 510 char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,k,a[N],f[N*N],t; signed main() { n=read(),k=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) f[++t]=a[i]+a[j]; sort(f+1,f+t+1);reverse(f+1,f+t+1); ll ans=0; for (int i=1;i<=k;i++) ans+=f[i]; cout<<ans; return 0; //NOTICE LONG LONG!!!!! }
B:找到第一個和最後一個有1的列,狀壓dp一下即可,即設f[i][0/1][0/1]為第i列為0/1,0/1時的最優方案要加多少個1。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 100010 char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,a[N][2],f[N][2][2],first,last,ans; signed main() { n=read(); for (int i=1;i<=n;i++) a[i][0]=read(); for (int i=1;i<=n;i++) a[i][1]=read(); for (int i=1;i<=n;i++) if (a[i][0]||a[i][1]) {first=i;break;} for (int i=n;i>=1;i--) if (a[i][0]||a[i][1]) {last=i;break;} memset(f,42,sizeof(f));f[first-1][1][1]=0; for (int i=first;i<=last;i++) { for (int x0=0;x0<2;x0++) for (int x1=0;x1<2;x1++) for (int y0=0;y0<2;y0++) for (int y1=0;y1<2;y1++) { int tot=0; if (a[i][0]==0&&x0==1) tot++; if (a[i][1]==0&&x1==1) tot++; if (x0==1&&y0==1||x1==1&&y1==1) f[i][x0][x1]=min(f[i][x0][x1],f[i-1][y0][y1]+tot); } } ans=1000000000; for (int i=0;i<2;i++) for (int j=0;j<2;j++) ans=min(ans,f[last][i][j]); cout<<ans; return 0; //NOTICE LONG LONG!!!!! }
C:容易發現子序列中一個數的貢獻是2l,而只需要考慮其是否是m的倍數,於是l超過logm後就沒什麽意義了。於是設f[i][j][k]為前i個數選了模m為j的k個數的方案數,轉移顯然。復雜度O(nmlogm),直接就可以暴力過去。事實上應該是可以做到O(nm)的,因為只需要考慮模m/2k的值。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 5010 #define P 1000000007 char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N],f[15][N],g[N],t; inline void inc(int &x,int y){x+=y;if (x>=P) x-=P;} inline int dec(int x,int y){x-=y;if (x<0) x+=m;return x;} signed main() { n=read(),m=read();int tmp=m;while (tmp%2==0) t++,tmp>>=1;t++; for (int i=1;i<=n;i++) a[i]=read(); f[0][0]=1; for (int i=1;i<=n;i++) { for (int j=0;j<m;j++) g[j]=f[t][j]; for (int j=0;j<m;j++) inc(f[t][j],g[dec(j,a[i])]); for (int k=t;k;k--) { for (int j=0;j<m;j++) { inc(f[k][j],f[k-1][dec(j,a[i])]); } } } int ans=0; for (int i=0;i<m;i++) for (int j=1;j<=t;j++) { int x=i;for (int _=1;_<j;_++) x=(x<<1)%m; if (x==0) inc(ans,f[j][i]); } cout<<ans; return 0; //NOTICE LONG LONG!!!!! }
D:差分序列,則區間修改變成單點修改,然後只要維護區間線性基即可,註意要強制令第一個數是否選,這樣才能考慮完選偶數個數和奇數個數的情況。開始莫名其妙想成了前綴和,然後發現了一個選奇數個數的最大異或和的做法,即將每個數比最高位更高的一位設為1。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 50010 #define P 1000000007 #define uint int char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();} while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,L[N<<2],R[N<<2],tree_o[N]; int a[N],mx; void modify_o(int x,int y){while (x<=n) tree_o[x]^=y,x+=x&-x;} int query_o(int x){int s=0;while (x) s^=tree_o[x],x-=x&-x;return s;} struct base { int b[32]; void ins(int v) { for (int i=30;~i;i--) if (v&(1<<i)) { if (b[i]==0) {b[i]=v;return;} else v^=b[i]; } } int work(int v) { for (int i=30;~i;i--) v=max(v,v^b[i]); return v; } void clear(){memset(b,0,sizeof(b));} }tree[N<<2],e; base merge(base x,base y) { for (int i=30;~i;i--) if (x.b[i]) y.ins(x.b[i]); return y; } void build(int k,int l,int r) { L[k]=l,R[k]=r; if (l==r) {tree[k].ins(a[l]);return;} int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); tree[k]=merge(tree[k<<1],tree[k<<1|1]); } void modify(int k,int x,int p) { if (L[k]==R[k]) {tree[k].clear();a[x]^=p;modify_o(x,p);tree[k].ins(a[x]);return;} int mid=L[k]+R[k]>>1; if (x<=mid) modify(k<<1,x,p); else modify(k<<1|1,x,p); tree[k]=merge(tree[k<<1],tree[k<<1|1]); }//給x xor 上p base query(int k,int l,int r) { if (l>r) return e; if (L[k]==l&&R[k]==r) return tree[k]; int mid=L[k]+R[k]>>1; if (r<=mid) return query(k<<1,l,r); else if (l>mid) return query(k<<1|1,l,r); else return merge(query(k<<1,l,mid),query(k<<1|1,mid+1,r)); }//區間線性基 signed main() { n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=n;i;i--) a[i]^=a[i-1],modify_o(i,a[i]); build(1,0,n); while (m--) { int op=read(),l=read(),r=read(); int v=read(); if (op==1) { modify(1,l,v); if (r<n) modify(1,r+1,v); } else { int ans=max(query(1,l+1,r).work(v),query(1,l+1,r).work(v^query_o(l))); printf("%d\n",ans); } } return 0; //NOTICE LONG LONG!!!!! }
小裙子!
Comet OJ Contest #3