17-09-13模拟赛

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 }
原文地址:https://www.cnblogs.com/codingutopia/p/test170913.html