T1:可以发现,满足题设条件的方案只有三个位置成一行或是三个位置成直角。
记录每一行与列白色方格的个数,由此求得红色方格的个数。
对于成行或成列的情况,分别求出中间是红色或白色的情况的方案个数。
对于成直角的情况,则枚举直角顶点,计算其对应行与对应列的方案个数。
注意答案可能会超过long long范围。
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define ll long long 5 #define mod 1000000000000000000 6 #define MN 4000005 7 #define row(x) (sum[x]) 8 #define col(x) (sum[x+n]) 9 using namespace std; 10 inline int in(){ 11 int x=0;bool f=0; char c; 12 for (;(c=getchar())<'0'||c>'9';f=c=='-'); 13 for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0'); 14 return f?-x:x; 15 } 16 struct exll{ 17 ll a[2]; 18 }ans; 19 ll sum[MN]; 20 inline exll operator +(const exll &x,const ll &y){ 21 exll z;memset(z.a,0,sizeof(z.a)); 22 z.a[1]=x.a[1]+y;z.a[0]=x.a[0]+(z.a[1]/mod);z.a[1]%=mod;return z; 23 } 24 char s[MN]; 25 int n,m; 26 int main() 27 { 28 n=in();m=in();memset(ans.a,0,sizeof(ans.a)); 29 for (int i=0;i<n;++i){ 30 scanf("%s",s+i*m);for (int j=0;j<m;++j) 31 row(i)+=1ll*(s[i*m+j]-'0'),col(j)+=1ll*(s[i*m+j]-'0'); 32 }for (int i=0;i<n;++i)ans=ans+1ll*(row(i)*(m-row(i))*(m-row(i)-1)),ans=ans+1ll*(row(i)*(row(i)-1)*(m-row(i))); 33 for (int i=0;i<m;++i) ans=ans+1ll*(col(i)*(n-col(i))*(n-col(i)-1)),ans=ans+1ll*(col(i)*(col(i)-1)*(n-col(i))); 34 for (int i=0;i<n;++i) 35 for (int j=0;j<m;++j){ 36 if (s[i*m+j]=='1') ans=ans+2ll*((m-row(i))*(n-col(j))); 37 else ans=ans+2ll*(row(i)*col(j)); 38 }if (ans.a[0]) printf("%lld%018lld",ans.a[0],ans.a[1]); 39 else printf("%lld",ans.a[1]);return 0; 40 }
T2:可以发现,对对一个数取φ会使该数的值以极快的速率下降。
对一个大于1的奇数取φ,结果一定是偶数;对一个偶数取φ,结果一定小等于该数的一半;φ(1)=1.
所以一个数最多取log级别次φ就能变为1.
考虑用欧拉筛O(值域)求φ,而后用线段树维护序列的区间最大值和区间乘积。
每次修改定位到一个区间后,如果该区间内最大值超过1,则继续往下递归,否则不用直接返回上一级;
或者直到递归到长度为1的区间后,直接将该值取φ即可。修改的复杂度最多为O(n log n).
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define ll long long 5 #define L (x<<1) 6 #define R (x<<1|1) 7 #define mid ((l+r)>>1) 8 #define mod 1000000007 9 #define MN 200005 10 #define MV 10000005 11 using namespace std; 12 inline int in(){ 13 int x=0;bool f=0; char c; 14 for (;(c=getchar())<'0'||c>'9';f=c=='-'); 15 for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0'); 16 return f?-x:x; 17 } 18 int mx[MN<<2],a[MN],phi[MV],pri[MV]; 19 int n,m,tp,x,y,mn=0,cnt=0; 20 ll pro[MN<<2]; 21 inline void getphi(int n){ 22 phi[1]=1;for (int i=2;i<n;++i){ 23 if (!phi[i]) pri[++cnt]=i,phi[i]=i-1; 24 for (int j=1;i*pri[j]<n&&j<=cnt;++j){ 25 if (i%pri[j]) phi[i*pri[j]]=phi[i]*phi[pri[j]]; 26 else {phi[i*pri[j]]=phi[i]*pri[j];break;} 27 } 28 } 29 } 30 inline void pushup(int x){ 31 mx[x]=max(mx[L],mx[R]);pro[x]=1ll*pro[L]*pro[R]%mod; 32 } 33 inline void pushdown(int x,int l,int r){ 34 if (mx[x]==1) return; 35 if (l==r) {mx[x]=pro[x]=phi[mx[x]];return;} 36 pushdown(L,l,mid);pushdown(R,mid+1,r);pushup(x); 37 } 38 inline void update(int x,int l,int r,int a,int b){ 39 if (a<=l&&b>=r) {pushdown(x,l,r);return;} 40 if (a<=mid) update(L,l,mid,a,b); 41 if (b>mid) update(R,mid+1,r,a,b);pushup(x); 42 } 43 inline ll query(int x,int l,int r,int a,int b){ 44 if (a<=l&&b>=r) return pro[x]; 45 if (b<=mid) return query(L,l,mid,a,b); 46 else if (a>mid) return query(R,mid+1,r,a,b); 47 else return 1ll*query(L,l,mid,a,mid)*query(R,mid+1,r,mid+1,b)%mod; 48 } 49 inline void build(int x,int l,int r){ 50 if (l==r){mx[x]=pro[x]=a[l];return;} 51 build(L,l,mid);build(R,mid+1,r);pushup(x); 52 } 53 int main() 54 { 55 n=in();m=in();for (int i=1;i<=n;++i) 56 a[i]=in(),mn=max(mn,a[i]);getphi(mn+1);build(1,1,n); 57 for (int i=1;i<=m;++i){ 58 tp=in();x=in();y=in(); 59 if (tp==1) update(1,1,n,x,y); 60 else printf("%lld ",query(1,1,n,x,y)); 61 }return 0; 62 }
T3:最大权闭合子图,即二分图匹配。
观察到质数除了2以外都是奇数,所以起冲突的两个数奇偶性必定不同,所以将奇数分为一边,偶数分为一边。
又因为构成2两数之和的只有1+1,又因为乘以1对答案没有影响,所以读入时可以舍弃1的情况。
建图时对每个数取对数,变为求和最大。
S向每个奇数连边权为log(权值)的边,每个偶数向T连边权为log(权值)的边,有冲突的点之间连边,边权为inf.
得出答案时,从S开始dfs,每次只走满流的边。
对于左边的点,如果能遍历到,那么把它加入答案;对于右边的点,如果不能遍历到,把它加入答案。
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<queue> 6 #define ll long long 7 #define ld long double 8 #define MN 1000005 9 #define MM 5005 10 #define mod 1000000007 11 #define inf 0x7fffffff 12 #define eps 1e-12 13 using namespace std; 14 inline int in(){ 15 int x=0;bool f=0; char c; 16 for (;(c=getchar())<'0'||c>'9';f=c=='-'); 17 for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0'); 18 return f?-x:x; 19 } 20 struct edge{ 21 int to,next; 22 ld cap; 23 }e[MN<<1]; 24 int head[MM],iter[MM],lev[MM],b[2][MM]; 25 int cnt=1,s,t,n,x; 26 bool vis[MM],np[MN]; 27 inline void ins(int x,int y,ld cp){ 28 e[++cnt].to=y;e[cnt].next=head[x];head[x]=cnt;e[cnt].cap=cp; 29 e[++cnt].to=x;e[cnt].next=head[y];head[y]=cnt;e[cnt].cap=0; 30 } 31 inline void getp(int n){ 32 np[1]=1;for (int i=2;i*i<n;++i) 33 if (!np[i]) for (int j=i;i*j<n;++j)np[i*j]=1; 34 } 35 inline void bfs(){ 36 queue<int>q;memset(lev,-1,sizeof(lev)); 37 lev[s]=0;q.push(s); 38 while (!q.empty()){ 39 int u=q.front();q.pop(); 40 for (int i=head[u];i;i=e[i].next){ 41 int v=e[i].to; 42 if (e[i].cap>eps&&lev[v]==-1) 43 lev[v]=lev[u]+1,q.push(v); 44 } 45 } 46 } 47 inline ld dfs(int u,ld f){ 48 if (u==t) return f;ld used=0.0; 49 for (int &i=iter[u];i;i=e[i].next){ 50 int v=e[i].to; 51 if (e[i].cap>eps&&lev[u]+eps<lev[v]){ 52 ld w=dfs(v,min(f-used,e[i].cap)); 53 if (w>eps){ 54 e[i].cap-=w;e[i^1].cap+=w;used+=w; 55 if (used==f) return f; 56 } 57 } 58 }return used; 59 } 60 inline void dinic(){ 61 while (1){ 62 bfs();if (lev[t]==-1) return; 63 memcpy(iter,head,sizeof(head)); 64 ld d=0.0;while ((d=dfs(s,inf))>eps); 65 } 66 } 67 inline void dfs2(int u){ 68 for (int i=head[u];i;i=e[i].next){ 69 int v=e[i].to; 70 if (e[i].cap>eps&&!vis[v]) vis[v]=1,dfs2(v); 71 } 72 } 73 int main() 74 { 75 n=in();getp(MN+1);s=0;t=n+1; 76 for (int i=1;i<=n;++i){x=in();if (x==1) continue;b[x&1][++b[x&1][0]]=x;} 77 for (int i=1;i<=b[0][0];++i) ins(s,i,log2(b[0][i])); 78 for (int i=1;i<=b[1][0];++i) ins(i+b[0][0],t,log2(b[1][i])); 79 for (int i=1;i<=b[0][0];++i) 80 for (int j=1;j<=b[1][0];++j) 81 if (!np[b[0][i]+b[1][j]]) ins(i,j+b[0][0],inf); 82 dinic();vis[s]=1;dfs2(s);ll ans=1ll; 83 for (int i=1;i<=b[0][0];++i) if (vis[i]) ans=1ll*ans*b[0][i]%mod; 84 for (int i=1;i<=b[1][0];++i) if (!vis[i+b[0][0]]) ans=1ll*ans*b[1][i]%mod; 85 printf("%lld",ans);return 0; 86 }