2017 Multi-University Training Contest - Team 4
rank 75/739
1003 Counting Divisors
筛法求出l到r区间内各个数字质因子的个数,对于每个数,d(x) = ∏(1+k*pi),pi为质因子指数。
#include <bits/stdc++.h> using namespace std; const int maxn=1000005; const long long mod=998244353; int T,tot; bool is_prime[maxn]; long long l,r,K,prime[maxn],num[maxn],temp[maxn]; vector<long long> G[maxn]; int sieve() { int p=0; memset(is_prime,0,sizeof is_prime); is_prime[0]=is_prime[1]=1; for (int i=2;i<maxn;++i) { if (!is_prime[i]) { prime[p++]=i; for (int j=2*i;j<maxn;j+=i) is_prime[j]=1; } } return p; } void print() { for (int i=0;i<=r-l;++i) { printf("%I64d: ",i+l); for (int j=0;j<(int)G[i].size();++j) printf("%I64d ",G[i][j]); putchar('\n'); } } int main() { tot=sieve(); scanf("%d",&T); while (T--) { scanf("%I64d%I64d%I64d",&l,&r,&K); for (long long i=0;i<=r-l;++i) num[i]=i+l,temp[i]=1; for (int i=0;i<tot;++i) { long long p=prime[i]; for (long long j=(l+p-1)/p*p;j<=r;j+=p) { long long &tj=num[j-l]; long long cnt=0; while (tj%p==0) { tj/=p; ++cnt; } temp[j-l]=temp[j-l]*(K*cnt+1)%mod; } } for (int i=0;i<=r-l;++i) if (num[i]>1) temp[i]=(temp[i]*(K+1))%mod; long long res=0; for (int i=0;i<=r-l;++i) res=(res+temp[i])%mod; cout<<res<<endl; } return 0; }
1004 Dirt Ratio
二分答案[0,1]C,区间内种类个数M,区间长度N,那么有M/N <= c 为 true。转化为M - C * N <= 0。遍历N,线段树维护以i为结尾的答案,如果1,i区间最小值小于等于0 返回true。
#include <bits/stdc++.h> const long long mod = 1e9+7; const double ex = 1e-10; #define inf 0x3f3f3f3f using namespace std; map <int ,int> M; int a[60005]; const int maxn = 60005; struct node { double val; double addmark; } ST[4*maxn+5]; double A[maxn]; int N; //修改求和还是维护区间最小值 double operation(double a,double b) { //return a+b; return min(a,b); } //修改求和还是维护区间最小值 void change(int pos,double addmark,int l) { ST[pos].val +=addmark; } void build(int root,int ibegin,int iend) { ST[root].addmark = 0; if (ibegin==iend) ST[root].val = A[ibegin]; else { int mid = (ibegin+iend)/2; build(2*root,ibegin,mid); build(2*root+1,mid+1,iend); ST[root].val = operation(ST[root*2].val,ST[root*2+1].val); } } void push_down(int root,int l) { if (ST[root].addmark == 0) return; double addmark = ST[root].addmark; ST[root*2].addmark+=addmark; ST[root*2+1].addmark+=addmark; change(root*2,addmark,l-l/2); change(root*2+1,addmark,l/2); ST[root].addmark = 0; } double query(int root,int ibegin,int iend,int qbegin,int qend) { if (ibegin > qend || iend < qbegin) return 1e233;// if (ibegin>=qbegin&&iend<=qend) return ST[root].val; push_down(root,iend-ibegin+1); int mid = (ibegin+iend)/2; return operation(query(root*2,ibegin,mid,qbegin,qend),query(root*2+1,mid+1,iend,qbegin,qend)); } void updata(int root,int ibegin,int iend,int qbegin,int qend,double addmark) { if (ibegin > qend || iend < qbegin) return ;// if (ibegin>=qbegin&&iend<=qend) { ST[root].addmark+=addmark; change(root,addmark,iend-ibegin+1); return; } push_down(root,iend-ibegin+1); int mid = (ibegin+iend)/2; updata(root*2,ibegin,mid,qbegin,qend,addmark); updata(root*2+1,mid+1,iend,qbegin,qend,addmark); ST[root].val = operation(ST[root*2].val,ST[root*2+1].val); } int last[60005]; int t[60005]; bool check(double ans) { for (int i = 1; i<=N; i++) A[i] = 0; build(1,1,N); for (int i = 1;i<=N; i++) { updata(1,1,N,last[i]+1,i,1.0); updata(1,1,N,1,i,-ans); if (query(1,1,N,1,i) < 0) return true; } return false; } int main() { int T; scanf("%d",&T); while (T--) { scanf("%d",&N); for (int i = 1;i<=N;i++) t[i] = last[i] = 0; for (int i = 1;i<=N;i++) { scanf("%d",&a[i]); if (t[a[i]] == 0) { last[i] = 0; } else { last[i] = t[a[i]]; } t[a[i]] = i; } int cnt = 0; double l = 0; double r = 1+ex; while (cnt++<=15) { double mid = (l+r)/2; if (check(mid)) r = mid; else l = mid; } printf("%.10f\n",l); } return 0;
1005 Lazy Running
取左右最小值W,转化为最短路,求%2*W的最短路。可以知道能够通过所求最短路和 重复来回走T次W来构造所有可能。
#include <bits/stdc++.h> const long long mod = 1e9+7; const double ex = 1e-10; #define inf 0x3f3f3f3f3f3f3f3f using namespace std; long long dis[6][60002]; int inq[6][60002]; long long a[6][6]; typedef pair<int,long long> pii; long long W; void spfa() { memset(dis,inf,sizeof(dis)); memset(inq,0,sizeof(inq)); queue <pii> Q; Q.push(make_pair(1,0)); dis[1][0] = 0; inq[1][0] = 1; while (!Q.empty()){ int u = Q.front().first; long long k = Q.front().second; if (dis[(u+1)%4][( k + a[u][ (u+1) % 4 ] ) % (2*W)]>dis[u][k] + (long long) a[u][ (u+1) % 4 ]){ dis[(u+1)%4][( k + a[u][ (u+1) % 4 ] ) % (2*W)] = dis[u][k] + (long long)a[u][ (u+1) % 4 ]; if (!inq[(u+1)%4][( k + a[u][ (u+1) % 4 ] ) % (2*W)]){ Q.push(make_pair((u+1)%4,( k + a[u][ (u+1) % 4 ] ) % (2*W))); inq[(u+1)%4][( k + a[u][ (u+1) % 4 ] ) % (2*W)] = 1; } } if (dis[(u+3)%4][( k + a[u][ (u+3) % 4 ] ) % (2*W)]>dis[u][k] + (long long) a[u][ (u+3) % 4 ]){ dis[(u+3)%4][( k + a[u][ (u+3) % 4 ] ) % (2*W)] = dis[u][k] + (long long)a[u][ (u+3) % 4 ]; if (!inq[(u+3)%4][( k + a[u][ (u+3) % 4 ] ) % (2*W)]){ Q.push(make_pair((u+3)%4,( k + a[u][ (u+3) % 4 ] ) % (2*W))); inq[(u+3)%4][( k + a[u][ (u+3) % 4 ] ) % (2*W)] = 1; } } Q.pop(); inq[u][k] = 0; } } int main() { int N; cin >> N; while (N--){ long long K; cin >> K; for (int i = 0; i<=3; i++){ long long t; cin >> t; a[i][(i+1)%4] = t; a[(i+1)%4][i] = t; } W = min(a[1][2],a[0][1]); spfa(); long long ans = inf; for (int i = 0 ; i<2*W ; i++){ if (dis[1][i]>=K) ans = min(ans,dis[1][i]); else ans = min (ans,dis[1][i] + 2*W *((K-dis[1][i] + 2*W-1)/(2*W)) ); } cout << ans <<endl; } return 0; }
1007 Matching In Multiplication【补】
一个特殊的二分图,找到图上的环,对于环上的点分为两种选择分为ai,bi;找到图上的链,对于这部分链,选择唯一为cj。所有完美匹配的乘积的和显然就是(ai+bi)cj。
#include <bits/stdc++.h> using namespace std; const int maxn=300015; const long long mod=998244353; typedef pair<int,long long> pil; int deg[maxn],T,n,vis[maxn<<1],tot,head[maxn<<1],ok,pb,used[maxn<<1]; long long temp[maxn][2],res; vector<long long> cir; queue <int> Q; struct ee { int to,next; long long w; bool flag; } edge[maxn<<2]; void addedge(int u,int v,long long w) { edge[tot].w=w; edge[tot].to=v; edge[tot].next=head[u]; edge[tot].flag=0; head[u]=tot++; edge[tot].w=w; edge[tot].to=u; edge[tot].next=head[v]; edge[tot].flag=0; head[v]=tot++; }; void dfs(int u,int fa) { if (used[u]) return; if (vis[u]&&!used[u]) { ok=1; pb=u; return; } vis[u]=1; for (int i=head[u];~i;i=edge[i].next) { if (edge[i].flag) continue; if (edge[i].to == fa) continue; dfs(edge[i].to,u); if (ok) { edge[i].flag=true; edge[i^1].flag=true; cir.push_back(edge[i].w); used[u]=1; if (pb==u) ok=0; return; } } } void dfs2(int u,int col) { vis[u]=1; for (int i=head[u];~i;i=edge[i].next) { if (edge[i].flag) continue; if (vis[edge[i].to]) continue; if (!col){ res=res*edge[i].w%mod; dfs2(edge[i].to,!col); } else{ deg[edge[i].to-n]--; if (deg[edge[i].to-n] == 1) dfs2(edge[i].to,!col); } } } int main() { scanf("%d",&T); while (T--) { scanf("%d",&n); tot=0; memset(vis,0,(2*n+2)*sizeof vis[0]); memset(head,-1,(2*n+2)*sizeof head[0]); memset(deg,0,(n+1)*sizeof deg[0]); memset(used,0,(2*n+2)*sizeof used[0]); for (int i=1;i<=n;++i) { int v1,v2; long long w1,w2; scanf("%d%I64d%d%I64d",&v1,&w1,&v2,&w2); addedge(i,v1+n,w1); addedge(i,v2+n,w2); ++deg[v1]; ++deg[v2]; } for (int i=0;i<=n;++i) temp[i][0]=temp[i][1]=1; int cnt=0; for (int i=1;i<=n;++i) if (!vis[i]) { ok=0; cir.clear(); dfs(i,-1); if (cir.size()==0) continue; ++cnt; for (int j=0;j<(int)cir.size();++j) temp[cnt][j&1]=temp[cnt][j&1]*cir[j]%mod; } res=1; for (int i=1;i<=cnt;++i) res=res*((temp[i][0]+temp[i][1])%mod)%mod; memset(vis,0,sizeof vis); for (int i=n+1;i<=(n<<1);++i) if (deg[i-n]==1) dfs2(i,0); cout<<res<<endl; } return 0; }
1009 Questionnaire
m = 2 的时候显然模数只有0或1,取多的那个。
#include <bits/stdc++.h> using namespace std; int T,cnta,cntb,t,n,res; int main() { scanf("%d",&T); while (T--) { cnta=cntb=0; scanf("%d",&n); for (int i=1;i<=n;++i) { scanf("%d",&t); if (t&1) ++cnta; else ++cntb; } if (cnta>cntb) res=1; else res=0; printf("2 %d\n",res); } return 0; }
1011 Time To Get Up
模拟
#include <bits/stdc++.h> const long long mod = 1e9+7; const double eX = 1e-10; #define inf 0X3f3f3f3f using namespace std; string s[10]; string ans[10]; int get(int u) { if (s[2][u+2] == 'X') return 10; else if (s[1][u+2]=='X'&&s[4][u+2]=='X'&&s[2][u]=='X'&&s[2][u+3]=='X'&&s[5][u]=='X'&&s[5][u+3]=='X'&&s[7][u+2]=='X') return 8; else if (s[1][u+2]=='X'&&s[4][u+2]=='.'&&s[2][u]=='X'&&s[2][u+3]=='X'&&s[5][u]=='X'&&s[5][u+3]=='X'&&s[7][u+2]=='X') return 0; else if (s[1][u+2]=='.'&&s[4][u+2]=='.'&&s[2][u]=='.'&&s[2][u+3]=='X'&&s[5][u]=='.'&&s[5][u+3]=='X'&&s[7][u+2]=='.') return 1; else if (s[1][u+2]=='X'&&s[4][u+2]=='X'&&s[2][u]=='.'&&s[2][u+3]=='X'&&s[5][u]=='X'&&s[5][u+3]=='.'&&s[7][u+2]=='X') return 2; else if (s[1][u+2]=='X'&&s[4][u+2]=='X'&&s[2][u]=='.'&&s[2][u+3]=='X'&&s[5][u]=='.'&&s[5][u+3]=='X'&&s[7][u+2]=='X') return 3; else if (s[1][u+2]=='.'&&s[4][u+2]=='X'&&s[2][u]=='X'&&s[2][u+3]=='X'&&s[5][u]=='.'&&s[5][u+3]=='X'&&s[7][u+2]=='.') return 4; else if (s[1][u+2]=='X'&&s[4][u+2]=='X'&&s[2][u]=='X'&&s[2][u+3]=='.'&&s[5][u]=='.'&&s[5][u+3]=='X'&&s[7][u+2]=='X') return 5; else if (s[1][u+2]=='X'&&s[4][u+2]=='X'&&s[2][u]=='X'&&s[2][u+3]=='.'&&s[5][u]=='X'&&s[5][u+3]=='X'&&s[7][u+2]=='X') return 6; else if (s[1][u+2]=='X'&&s[4][u+2]=='.'&&s[2][u]=='.'&&s[2][u+3]=='X'&&s[5][u]=='.'&&s[5][u+3]=='X'&&s[7][u+2]=='.') return 7; else return 9; } int main() { ios::sync_with_stdio(false); int N; cin >> N; while (N--) { for (int i = 1; i<=7;i++) cin >> s[i]; cout <<get(0)<<get(5)<<":"<<get(12)<<get(17)<<endl; } return 0; }