Day1
T1:
大意:一个850个点,8500条边的图,问所有点对之间的最小割有多少种不同的权值。至于为什么这就是所有的n-1种最小割...我也不太清楚。
T1贴一发别人的代码。。
//Copyright(c)2016 liuchenrui #include<bits/stdc++.h> #define short unsigned short #define inf 1000000000 using namespace std; template<typename T> inline void splay(T &v){ v=0;char c=0;T p=1; while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();} while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();} v*=p; } struct Edge{ short to,next;int flow; }edge[1000010]; short first[851],size; short deep[851],dl[851]; void addedge(short x,short y,int z){ size++; edge[size].to=y; edge[size].next=first[x]; first[x]=size; edge[size].flow=z; } void add(short x,short y,int z){ addedge(x,y,z),addedge(y,x,0); } short aim; int dfs(short now,int flow){ if(now==aim)return flow; int F=0; for(short u=first[now];u&&flow;u=edge[u].next){ if(deep[edge[u].to]==deep[now]+1&&edge[u].flow){ int tmp=dfs(edge[u].to,min(flow,edge[u].flow)); F+=tmp;edge[u].flow-=tmp;edge[u^1].flow+=tmp;flow-=tmp; } } if(!F)deep[now]=-5; return F; } bool bfs(short S,short T){ memset(deep,0,sizeof(deep)); dl[1]=S;deep[S]=1; short head=0,tail=1; while(head!=tail){ head++; for(int u=first[dl[head]];u;u=edge[u].next){ if(!deep[edge[u].to]&&edge[u].flow){ dl[++tail]=edge[u].to; deep[edge[u].to]=deep[dl[head]]+1; } } } return deep[T]; } int maxflow(short S,short T){ int ret=0;aim=T; while(bfs(S,T)){ ret+=dfs(S,inf); } return ret; } short fr[8600],to[8600]; int fl[8600]; int ans[1000010]; short cnt,n,m,p[851]; void rebuild(){ memset(first,0,sizeof first); size=1; for(int k=1;k<=m;k++){ add(fr[k],to[k],fl[k]); add(to[k],fr[k],fl[k]); } } bool vis[860]; void dfs2(short now){ vis[now]=1; for(int u=first[now];u;u=edge[u].next){ if(edge[u].flow&&!vis[edge[u].to]){ dfs2(edge[u].to); } } } void cdq_calc(short l,short r){ if(l>=r)return; rebuild(); ans[++cnt]=maxflow(p[l],p[r]); memset(vis,0,sizeof vis); dfs2(p[l]);int t=l-1; for(short i=l;i<=r;i++){ if(vis[p[i]]){ swap(p[i],p[++t]); } } cdq_calc(l,t),cdq_calc(t+1,r); } int main(){ splay(n),splay(m); for(short i=1;i<=m;i++){ splay(fr[i]),splay(to[i]),splay(fl[i]); } for(short i=1;i<=n;i++){ p[i]=i; } cdq_calc(1,n); sort(ans+1,ans+cnt+1); cnt=unique(ans+1,ans+cnt+1)-ans-1; printf("%d\n",cnt); //cerr<<clock()<<endl; }
首先YY了一个性质,对于两个凸包内的点a,b,一定有一个凸包上的点x使得max(ax,bx) > ab,有了这个性质我们就以知道,凸包内的一条边ab被访问,一定会在ax或者bx之后,而对于x点的最远点可以旋转卡壳得到。那么现在我们就定义凸包上的点是激活的,同时凸包内的点一开始是未激活的,一个点a被激活仅当ax是当前的最优解。比如现在的最优解是ax,我们令num[a]+1,num[x]+1,再求出a?的第num[a]+1大值,x?的num[x]+1大值,更新a和x的值,这个用堆维护就可以了。求第k大值也可以用堆维护(然而我并不会堆...强行线段树过之..),注意重点的情况,但是数据里好像没有(做凸包的时候注意一下就行了)...
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> #include <map> #define inf (((unsigned long long)1 << (unsigned long long)63) - (unsigned long long)1) #define Int long long using namespace std; struct point {Int x;Int y;int id; };point p[100010],q[100010],stack[200010]; Int val[800010],minx[850],maxx[850]; int E,belong[100010],cnt,n,k; int head,tail,father[100010],t,num[100010]; int tot[850]; map < pair<int,int>,int> mp; Int calc(point x,point y,point z) { point A,B; A.x = x.x - z.x; A.y = x.y - z.y; B.x = y.x - z.x; B.y = y.y - z.y; return A.x * B.y - A.y * B.x; } Int dis(point x,point y) { Int ret = (x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y); return ret; } bool comp(const point &x,const point &y) { Int v = calc(x,y,p[1]); if(v == 0) return dis(x,p[1]) < dis(y,p[1]); return v > 0; } void build(int Now,int l,int r) { val[Now] = -1; if(l == r) return; int Mid = (l + r) >> 1; build(Now << 1,l,Mid); build(Now << 1 | 1,Mid + 1,r); } void change(int Now,int l,int r,int x,Int y) { if(l == r) {val[Now] = y;return ;} int Mid = (l + r) >> 1; if(x <= Mid) change(Now << 1,l,Mid,x,y); else change(Now << 1 | 1,Mid + 1,r,x,y); if(val[Now << 1] > val[Now << 1 | 1]) val[Now] = val[Now << 1]; else val[Now] = val[Now << 1 | 1]; } int Ask(int Now,int l,int r) { if(l == r) return r; int Mid = (l + r) >> 1; if(val[Now << 1] == val[Now]) return Ask(Now << 1,l,Mid); else return Ask(Now << 1 | 1,Mid + 1,r); } int find(int Now,int l,int r) { if(l == r) return r; int Mid = (l + r) >> 1; if(minx[Now] == minx[Now << 1]) return find(Now << 1,l,Mid); else return find(Now << 1 | 1,Mid + 1,r); } void insert(int Now,int l,int r,int x,Int y) { if(l == r) {minx[Now] = maxx[Now] = y;tot[Now] = 1;return ;} int Mid = (l + r) >> 1; if(x <= Mid) insert(Now << 1,l,Mid,x,y); else insert(Now << 1 | 1,Mid + 1,r,x,y); tot[Now] = tot[Now << 1] + tot[Now << 1 | 1]; minx[Now] = min(minx[Now << 1],minx[Now << 1 | 1]); maxx[Now] = max(maxx[Now << 1],maxx[Now << 1 | 1]); } int bf(int x) { int Z = num[x] + 1; for(int i = 1;i <= 810;i ++) minx[i] = inf,maxx[i] = -1,tot[i] = 0; for(int i = 1;i <= n;i ++) { Int G = dis(q[i],q[x]); if(tot[1] < Z) insert(1,1,100,tot[1] + 1,G); else if(minx[1] < G) insert(1,1,100,find(1,1,100),G); } for(int i = 1;i <= n;i ++) if(dis(q[i],q[x]) == minx[1] && mp[make_pair(x,i)] == 0) return i; } int getint() { char c = 'd'; int ret = 0; while(c < '0' || c > '9') c = getchar(); while(c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar(); return ret; } int main() { n = getint(); k = getint(); for(int i = 1;i <= n;i ++) p[i].x = getint(),p[i].y = getint(),q[i].x = p[i].x,q[i].y = p[i].y,p[i].id = i; t = 1; for(int i = 2;i <= n;i ++) if(p[i].y < p[t].y || (p[i].y == p[t].y && p[i].x < p[t].x)) t = i; swap(p[1],p[t]); sort(p + 2,p + n + 1,comp); head = 1;tail = 0; for(int i = 1;i <= n;i ++) { while(head < tail && calc(p[i],stack[tail],stack[tail - 1]) >= 0) tail --; stack[ ++ tail] = p[i]; } for(int i = 1;i <= tail;i ++) stack[i + tail] = stack[i]; int M = 1; build(1,1,n); for(int i = 1;i <= tail;i ++) { while(M < 2 * tail && dis(stack[M + 1],stack[i]) >= dis(stack[M],stack[i])) M = M + 1; change(1,1,n,stack[i].id,dis(stack[i],stack[M]));father[stack[i].id] = stack[M].id; } for(int i = 1;i < k;i ++) { int t = Ask(1,1,n),w = father[t]; mp[make_pair(w,t)] = mp[make_pair(t,w)] = 1; num[t] ++; num[w] ++; father[t] = bf(t); father[w] = bf(w); change(1,1,n,t,dis(q[t],q[father[t]])); change(1,1,n,w,dis(q[w],q[father[w]])); } cout<<val[1]; }
感觉没什么特别的..应该是人人都会的送分题那种....(为什么我写得那么长。。。。)
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> using namespace std; long long f[12][10][4][2][2],l,r; int getnum(long long x) { int ret = 0; while(x > 0) x /= 10,ret ++; return ret; } long long get(int x) { if(x == -1) return 0; long long ret = 1; for(int i = 1;i <= x;i ++) ret = 1ll * ret * 10; return ret; } long long Ask(long long x,int pos,int pre,int L,bool A,bool B) { if(pos == 0) return 0; if(A && B) return 0; long long ret = 0; int M = x / get(pos - 1); if(pos == 11) { if(x < get(pos - 1)) return 0; for(int i = 1;i <= M - 1;i ++) ret += f[pos][i][3][0][0] + f[pos][i][3][0][1] + f[pos][i][3][1][0]; if(M == 4) ret += Ask(x - M * get(pos - 1),pos - 1,M,1,1,B); else if(M == 8) ret += Ask(x - M * get(pos - 1),pos - 1,M,1,A,1); else ret += Ask(x - M * get(pos - 1),pos - 1,M,1,A,B); return ret; } if(pos == 1) M = M + 1; if(L == 3) { if(A) { for(int i = 0;i <= M - 1;i ++) if(i != 8) { ret += f[pos][i][1][0][0] + f[pos][i][1][1][0]; ret += f[pos][i][2][0][0] + f[pos][i][2][1][0]; ret += f[pos][i][3][0][0] + f[pos][i][3][1][0]; } } else if(B) { for(int i = 0;i <= M - 1;i ++) if(i != 4) { ret += f[pos][i][1][0][0] + f[pos][i][1][0][1]; ret += f[pos][i][2][0][0] + f[pos][i][2][0][1]; ret += f[pos][i][3][0][0] + f[pos][i][3][0][1]; } } else { for(int i = 0;i <= M - 1;i ++) { ret += f[pos][i][1][0][0] + f[pos][i][1][1][0] + f[pos][i][1][0][1]; ret += f[pos][i][2][0][0] + f[pos][i][2][1][0] + f[pos][i][2][0][1]; ret += f[pos][i][3][0][0] + f[pos][i][3][1][0] + f[pos][i][3][0][1]; } } } else { if(A) { for(int i = 0;i <= M - 1;i ++) if(i != 8) { if(i == pre) for(int j = 3;j >= 3 - L;j --) ret += f[pos][i][j][0][0] + f[pos][i][j][1][0]; else ret += f[pos][i][3][0][0] + f[pos][i][3][1][0]; } } else if(B) { for(int i = 0;i <= M - 1;i ++) if(i != 4) { if(i == pre) for(int j = 3;j >= 3 - L;j --) ret += f[pos][i][j][0][0] + f[pos][i][j][0][1]; else ret += f[pos][i][3][0][0] + f[pos][i][3][0][1]; } } else { for(int i = 0;i <= M - 1;i ++) { if(i == pre) for(int j = 3;j >= 3 - L;j --) ret += f[pos][i][j][0][0] + f[pos][i][j][1][0] + f[pos][i][j][0][1]; else ret += f[pos][i][3][0][0] + f[pos][i][3][1][0] + f[pos][i][3][0][1]; } } } x = x - 1ll * M * get(pos - 1); if(M == pre) ret += Ask(x,pos - 1,M,min(L + 1,3),(M == 4 || A),(M == 8 || B)); else if(L == 3) ret += Ask(x,pos - 1,M,3,(M == 4 || A),(M == 8 || B)); else ret += Ask(x,pos - 1,M,1,(M == 4 || A),(M == 8 || B)); return ret; } void pre_work() { f[1][0][1][0][0] = 1; f[1][1][1][0][0] = 1; f[1][2][1][0][0] = 1; f[1][3][1][0][0] = 1; f[1][4][1][1][0] = 1; f[1][5][1][0][0] = 1; f[1][6][1][0][0] = 1; f[1][7][1][0][0] = 1; f[1][8][1][0][1] = 1; f[1][9][1][0][0] = 1; for(int i = 2;i <= 11;i ++) for(int j = 0;j <= 9;j ++) for(int w = 0;w <= 9;w ++) for(int k = 1;k <= 3;k ++) for(int g = 0;g <= 1;g ++) for(int h = 0;h <= 1;h ++) { if(j == 4) { if(k == 3) f[i][j][3][1][h] += f[i - 1][w][3][g][h]; else if(j == w) f[i][j][min(k + 1,3)][1][h] += f[i - 1][w][k][g][h]; else f[i][j][1][1][h] += f[i - 1][w][k][g][h]; } else if(j == 8) { if(k == 3) f[i][j][3][g][1] += f[i - 1][w][3][g][h]; else if(j == w) f[i][j][min(k + 1,3)][g][1] += f[i - 1][w][k][g][h]; else f[i][j][1][g][1] += f[i - 1][w][k][g][h]; } else { if(k == 3) f[i][j][3][g][h] += f[i - 1][w][3][g][h]; else if(j == w) f[i][j][min(k + 1,3)][g][h] += f[i - 1][w][k][g][h]; else f[i][j][1][g][h] += f[i - 1][w][k][g][h]; } } } int main() { cin>>l>>r; pre_work(); cout<<Ask(r,11,-1,1,0,0) - Ask(l - 1,11,-1,1,0,0); }
Day2
T1:题意感觉有点绕。。搞清楚已知条件之后发现就是一个大质数分解+一个拓展欧几里锝。直接上pollard rho即可。
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> using namespace std; long long E,N,c,p = 0,q,k,r,A,n,B; long long ksc(long long x,long long y) { long long ret = 0; while(y > 0) { if(y % 2 == 1) ret = (ret + x) % N; x = (x + x) % N; y = y / 2; } return ret; } long long f(long long x) {return (1ll * ksc(x,x) + 1ll * k) % N;} long long gcd(long long x,long long y) { if(y == 0) return x; return gcd(y,x % y); } long long find(long long x) { k = 1ll * ((rand() * rand() % N) * (rand() * rand() % N)) % N; long long a = f(1); long long b = f(f(1)); while(a != b) { long long y = abs(a - b); if(gcd(y,x) != 1) return gcd(x,y); a = f(a); b = f(f(b)); } return 0; } void work(long long x) { p = find(x); while(p == 0) p = find(x); q = x / p; } long long exgcd(long long x,long long y) { if(y == 0) {A = 1;B = 0;return x;} long long ret = exgcd(y,x % y); long long t = A; A = B; B = t - (x / y) * B; return ret; } long long ksm(long long x,long long y) { long long ret = 1; while(y > 0) { if(y % 2 == 1) ret = ksc(ret,x); x = ksc(x,x); y = y / 2; } return ret; } int main() { srand(127); cin>>E>>N>>c; work(N); r = (p - 1ll) * (q - 1ll); long long C = exgcd(E,r); long long t = r / C; A = ((A * (1 / C)) % t + t) % t; n = ksm(c,A); cout<<A<<' '<<n; }
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> using namespace std; int son[32000010][2],len,A[10],n,tot = 0,tim[32000010],cnt,s[50],q[100]; int getint() { int ret = 0; char g = 'd'; while(g < '0' || g > '9') g = getchar(); while(g >= '0' && g <= '9') ret = ret * 10 + g - '0',g = getchar(); return ret; } void insert(int x) { int Now = 0; for(int i = 1;i <= len;i ++) { int t = s[i] - 0; if(son[Now][t] == 0) { son[Now][t] = ++ tot; Now = tot; } else Now = son[Now][t]; } if(tim[Now] == 0) tim[Now] = x; } int Ask() { int ret = 0; int Now = 0; int tail = 0; for(int i = 1;i <= len;i ++) { int t = s[i] - 0; Now = son[Now][t]; if(Now == 0) break; if(tim[Now] != 0) { while(tail && tim[q[tail]] > tim[Now]) tail --; q[ ++tail] = Now; } } for(int i = 1;i <= tail;i ++) if(tim[q[i]] >= A[5] && tim[q[i]] <= A[6]) ret ++; return ret; } int main() { scanf("%d",&n); for(int i = 1;i <= n;i ++) { char c = 'd'; while(c != 'A' && c != 'Q') c = getchar(); if(c == 'A') { for(int j = 1;j <= 5;j ++) A[j] = getint(); for(int j = 1;j <= 4;j ++) for(int k = 8;k >= 1;k --) if(A[j] >= (1 << (k - 1))) s[(j - 1) * 8 + (8 - k + 1)] = 1,A[j] -= (1 << (k - 1)); else s[(j - 1) * 8 + (8 - k + 1)] = 0; len = min(32,A[5]); insert( ++cnt); } else { for(int j = 1;j <= 6;j ++) A[j] = getint(); for(int j = 1;j <= 4;j ++) for(int k = 8;k >= 1;k --) if(A[j] >= (1 << (k - 1))) s[(j - 1) * 8 + (8 - k + 1)] = 1,A[j] -= (1 << (k - 1)); else s[(j - 1) * 8 + (8 - k + 1)] = 0; len = 32; printf("%d\n",Ask()); } } return 0; }
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <queue> #include <cmath> #include <ctime> using namespace std; long long n,k; int p[100],tot = 0; bool visit[200]; struct cp { long long val;int x,y,z; cp(){} cp(long long _v,int _x,int _y,int _z){val = _v,x = _x,y = _y,z = _z;} bool operator < (const cp &b)const{return val < b.val;} }; priority_queue <cp> Q; int main() { //freopen("lx.in","r",stdin); //freopen("lx.out","w",stdout); cin>>n>>k; for(int i = 2;i <= 128;i ++) { if(visit[i] == false) p[ ++tot] = i; for(int j = 1;j <= tot && p[j] * i <= 128;j ++) { visit[i * p[j]] = true; if(i % p[j] == 0) break; } } for(int i = 1;i <= tot;i ++) { long long x = 1; for(int j = 1;x <= n / p[i];j ++) Q.push(cp(1ll * x * p[i],j,i - 1,i)),x = 1ll * x * p[i]; } for(int i = 1;i <= k - 1;i ++) { cp t = Q.top(); Q.pop(); if(t.x != 1) for(int j = t.y;j >= 1;j --) Q.push(cp(1ll * t.val / p[t.z] * p[j],t.x - 1,j,t.z)); } cp t = Q.top(); cout<<t.val; }