2011 Multi-University Training Contest 4 - Host by SDU
A.Color the Simple Cycle(polya计数+字符串匹配)
此题的难点在于确定置换的个数,由a[i+k]=a[i], e[i+k]=e[i]联想到KMP。
于是把原串和原串扩大两倍的目标串进行字符串匹配就能求出具体的置换。
这里的算法可以使用hash或者kmp。
然后套polya公式就行了。
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n) for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h) for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l) for((i) = (h); (i) >= (l); --(i)) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%lld\n", x) #define Read() freopen("data.in", "r", stdin) #define Write() freopen("data.out", "w", stdout); typedef long long LL; const double eps = 1e-6; const double PI = acos(-1.0); const int inf = 0x1F1F1F1F; using namespace std; const int N = 100010; const int MOD = 1000000007; int n; int pre[N]; bool vis[2][N]; int v[N], e[N]; int vv[N<<1], ee[N<<1]; void get_next(int P[]) { int i, j = -1; pre[0] = -1; for(i = 1; i < n; ++i) { while(j > -1 && P[j+1] != P[i]) j = pre[j]; if(P[j + 1] == P[i]) ++j; pre[i] = j; } } void kmp(int T[], int P[], int f) { get_next(P); int i, k; for(k = -1, i = 0; i < (n<<1); ++i) { while(k > -1 && P[k+1] != T[i]) k = pre[k]; if(P[k+1] == T[i]) ++k; if(k == n - 1) { vis[f][i - n + 1] = true; k = pre[k]; } } } LL Pow(LL a, int b) { LL res = 1; while(b) { if(b&1) res = (res*a)%MOD; a = (a*a)%MOD; b >>= 1; } return res; } int exp_gcd(int a, int b, int& x, int& y) { if(b == 0) { x = 1; y = 0; return a; } int d = exp_gcd(b, a%b, y, x); // x1 = y2, y1 = x2; y -= a/b*x; //y1 = x2 - (a/b)*y2 return d; } int Inv(int c) { int x, y; exp_gcd(c, MOD, x, y); return x < 0 ? x + MOD : x; } int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } int main() { //Read(); int T, c, cnt, i; LL ans; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &c); for(i = 0; i < n; ++i) {scanf("%d", &v[i]); vv[i] = vv[i+n] = v[i];} for(i = 0; i < n; ++i) {scanf("%d", &e[i]); ee[i] = ee[i+n] = e[i];} CL(vis, false); kmp(vv, v, 0); kmp(ee, e, 1); ans = cnt = 0; for(i = 1; i <= n; ++i) { if(vis[0][i] && vis[1][i]) { ans += Pow(c, gcd(i, n)); ans %= MOD; cnt++; //cout << pow(c, gcd(i, n)) << " " << gcd(i, n) << endl; } } ans = ans*Inv(cnt)%MOD; cout << ans << endl; } return 0; }
B.Catch the Theves(平面图最小割转对偶图最短路)
BZOJ 狼抓兔子的简化版。
C.Cubic Maze(待填坑)
D.Dragon Ball(线段树和单调栈优化DP)
容易得到DP方程 dp[i]=dp[j]+max(val[j+1,i]) (pre[i]<=j<i).
复杂度为O(n^2logn) 需要优化。
方程右边的max()可以通过单调栈O(n)求出。复杂度O(n^2).
我们可以发现,假设此时扫到了k 对于单调栈里维护的两个连续的数 a[i]和a[j] (i>j) 那么max[[j+1,i], k]=a[i].
此时这些转移点的右边最大值部分都是一样的,那么我们只要求出这些转移点的dp部分最小值就行了。用一个线段树维护dp值,可以在logn的时间求出。
但是这样还是行不通,一个单调递减序列足以达到最坏复杂度。
可以再用一个线段树来维护min(dp[j]+max(...))。
复杂度O(nlogn).
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> #include<queue> #include<algorithm> #include<vector> #include<stack> #include<list> #include<iostream> #include<map> using namespace std; #define inf 0x3f3f3f3f #define Max 100100 int max(int a,int b) { return a>b?a:b; } int min(int a,int b) { return a<b?a:b; } int dp[Max],t,n,typ[Max],val[Max],rec,q[Max],lef[Max]; struct node { int l,r,minx; int mid() { return (l+r)>>1; } }T[4*Max]; void build(int l,int r,int rt) { T[rt].l=l;T[rt].r=r; T[rt].minx=0; if(l==r) { // T[rt].max=val[l]; return ; } int mid=T[rt].mid(); build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); } void modify(int l,int rt,int data) { if(T[rt].l==T[rt].r) { T[rt].minx=data; return; } int mid=T[rt].mid(); if(l<=mid) modify(l,rt<<1,data); else modify(l,rt<<1|1,data); T[rt].minx=min(T[rt<<1].minx,T[rt<<1|1].minx); } void query(int l,int r,int rt) { if(T[rt].l==l&&T[rt].r==r) { rec=min(rec,T[rt].minx); return; } int mid=T[rt].mid(); if(l>=mid+1) query(l,r,rt<<1|1); else if(r<=mid) query(l,r,rt<<1); else { query(l,mid,rt<<1); query(mid+1,r,rt<<1|1); } } int main() { int i,j; scanf("%d",&t); while(t--) { scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&typ[i]); } for(i=1;i<=n;i++) { scanf("%d",&val[i]); } dp[0]=0; int top=0;int tail=1; build(0,n,1); q[0]=0; memset(lef,0,sizeof(lef)); for(i=1;i<=n;i++) { // int maxn=val[i]; while(tail>top+1&&val[i]>val[q[tail-1]]) tail--; q[tail]=i; tail++; dp[i]=inf; for(j=tail-1;j>top&&q[j]>lef[typ[i]];j--) { rec=inf; query(max(q[j-1],lef[typ[i]]),q[j]-1,1); // printf("a"); dp[i]=min(rec+val[q[j]],dp[i]); } modify(i,1,dp[i]); lef[typ[i]]=i; // printf("i %d dp %d\n",i,dp[i]); } printf("%d\n",dp[n]); } }
E.Invade the Mars(最短路变形)
这是个具有保护节点的最短路。 每个节点必须在到达他的所有前置节点之后才能访问它。
考虑在 堆优化dijkstra 判断入堆条件时 多加几个判断就ok了
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-3 # define MOD 100000007 # define INF ((LL)1<<60) # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int res=0, flag=0; char ch; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+(ch-'0'); return flag?-res:res; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=3005; //Code begin... struct Edge{int p, next, w;}edge[140005]; int head[N], cnt, num[N]; VI node[N]; bool vis[N]; LL dis[N], mark[N]; struct qnode{ int v; LL c; qnode(int _v=0,LL _c=0):v(_v),c(_c){} bool operator <(const qnode &r)const{return c>r.c;} }; void init() { mem(head,0); cnt=1; mem(num,0); FO(i,0,N) node[i].clear(); } void add_edge(int u, int v, int w) { edge[cnt].p=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; } void dij(int n, int start) { mem(vis,0); mem(mark,0); FOR(i,1,n) dis[i]=INF; priority_queue<qnode>que; while (!que.empty()) que.pop(); dis[start]=0; que.push(qnode(start,0)); qnode tmp; while (!que.empty()) { tmp=que.top(); que.pop(); int u=tmp.v; if (vis[u]) continue; FO(i,0,node[u].size()) { int v=node[u][i]; --num[v]; if (num[v]==0&&mark[v]) dis[v]=max(mark[v],dis[u]), que.push(qnode(v,dis[v])); } vis[u]=1; for (int i=head[u]; i; i=edge[i].next) { int v=edge[i].p; if (num[v]) { if (!mark[v]) mark[v]=dis[u]+edge[i].w; else mark[v]=min(mark[v],dis[u]+edge[i].w); } if (!num[v]&&!vis[v]&&dis[v]>dis[u]+edge[i].w) { dis[v]=dis[u]+edge[i].w; que.push(qnode(v,dis[v])); } } } } int main () { int T, n, m, u, v, w; scanf("%d",&T); while (T--) { init(); scanf("%d%d",&n,&m); while (m--) scanf("%d%d%d",&u,&v,&w), add_edge(u,v,w); FOR(i,1,n) { scanf("%d",num+i); FOR(j,1,num[i]) scanf("%d",&u), node[u].pb(i); } dij(n,1); printf("%lld\n",dis[n]); } return 0; }
F.Necklace(离线+树状数组)
BZOJ HH的项链的变形。
G.Euclidean Algorithm(数论综合)
题目需要求sigma(lcm(i,n))-sigma(gcd(i,n))是否能被c整除。
结合欧拉函数和积性函数可以推出这两个式子,最后用大整数质因子分解算法可以算出答案。
#include <stdio.h> #include <ctime> #include <algorithm> #include <stdlib.h> #include <math.h> const int TIME = 12; long long factor[100],fac_num[100]; int count; int cmp(const void *a,const void *b) { long long temp; temp = *(long long*)a-*(long long *)b; if(temp==0) return 0; else if(temp<0) return -1; else return 1; } long long gcd(long long a,long long b) { if(b==0) return a; return gcd(b,a%b); } long long multi_mod(long long a,long long b,long long n) { long long res = 0; a%=n; for(;b;b>>=1) { if(b&1) res = (res+a)%n; a<<=1; a%=n; } return res; } long long multi_exp(long long a,long long b,long long n) { long long res = 1; for(;b;b>>=1) { if(b&1) res = multi_mod(res,a,n); a = multi_mod(a,a,n); } return res; } bool witness(long long a,long long n) { long long m,x,y; int i,j = 0; m = n-1; while(m%2==0) { j++; m>>=1; } x = multi_exp(a,m,n); for(i = 1;i<=j;i++) { y = multi_exp(x,2,n); if(y==1&&x!=1&&x!=n-1) return false; x = y; } if(y!=1) return false; return true; } bool Miller_Rabin(long long n,int times) { int i; long long a; if(n==1) return false; if(n==2) return true; if(n%2==0) return false; for(i = 1;i<=times;i++) { a = rand()%(n-2)+2; if(!witness(a,n)) return false; } return true; } long long pollard_rho(long long n) { long long i = 1, x = (long long)fabs(1.0*(rand() % (n - 1))) + 1, y, k, d, c; y = x, k = 2; do { c = (long long)fabs(1.0*(rand() % (n - 1))) + 1; } while (c == 0 || c == 2); do { i++; d = gcd(n + y - x, n); if (d != 1 && d != n) return d; if (i == k) y = x, k <<= 1; x = (multi_mod(x, x, n) + n - c) % n; } while (y != x); return n; } void get_factor(long long n) { long long temp; if(n==1) return ; if(Miller_Rabin(n,TIME)==true) { factor[count++] = n; return ; } temp = n; while(temp>=n) temp = pollard_rho(temp); get_factor(temp); get_factor(n/temp); } int main() { long long n,c,temp1,temp2,temp3,keep; int count1,i,count2,T; srand(time(NULL)); scanf("%d",&T); while(T--) { scanf("%I64d%I64d",&n,&c); count = 0; get_factor(n); qsort(factor,count,sizeof(factor[0]),cmp); count1 = 0; count2 = 1; for(i = 1;i<count;i++) { if(factor[i]!=factor[i-1]) { factor[count1] = factor[i-1]; fac_num[count1++] = count2; count2 = 1; } else count2++; } factor[count1] = factor[count-1]; fac_num[count1++] = count2; temp1 = 1; for(i=0;i<count1;i++) { temp3 = (fac_num[i]+1)*multi_exp(factor[i],fac_num[i],c)-fac_num[i]*multi_exp(factor[i],fac_num[i]-1,c); temp3 = (temp3+c)%c; temp1*=temp3; temp1%=c; } temp2 = 1; for(i = 0;i<count1;i++) { keep = (factor[i]+1)*2*c; temp3 = (multi_exp(factor[i],2*fac_num[i]+1,keep)+1)%keep/(factor[i]+1); temp2*=temp3; temp2%=2*c; } temp3 = (temp2-1+2*c)%(2*c); temp2 = ((((n%(2*c))*temp3)%(2*c)/2)+n%c)%c; temp3 = (temp2-temp1+c)%c; if(temp3==0) printf("yes\n"); else printf("no\n"); } return 0; }
H.A pupil’s problem(水题)
韦达定理。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-3 # define MOD 100000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int res=0, flag=0; char ch; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+(ch-'0'); return flag?-res:res; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=10005; //Code begin... int main () { int T; LL a, b, c; scanf("%d",&T); while (T--) { scanf("%lld%lld%lld",&a,&b,&c); LL delta=b*b-4*a*c; if (delta<0) puts("NO"); else if (delta==0) printf("%.2f\n",-(double)b/2/a); else { double m=sqrt(delta), x1=(-b-m)/2/a, x2=(-b+m)/2/a; if (x1>x2) swap(x1,x2); printf("%.2f %.2f\n",x1,x2); } } return 0; }
I.Special sort(水题)
结构体排序。
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-3 # define MOD 100000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int res=0, flag=0; char ch; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+(ch-'0'); return flag?-res:res; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=10005; //Code begin... typedef struct{LL a, b, id, sum, eq;}Node; Node node[N]; bool comp(Node a, Node b) { if (a.sum!=b.sum) return a.sum>b.sum; if (a.eq!=b.eq) return a.eq>b.eq; return a.id<b.id; } int main () { int T, n; scanf("%d",&T); while (T--) { scanf("%d",&n); FOR(i,1,n) { scanf("%lld%lld",&node[i].a,&node[i].b); node[i].id=i; node[i].sum=node[i].a+node[i].b; if (node[i].a>node[i].b) node[i].eq=2; else if (node[i].a==node[i].b) node[i].eq=1; else node[i].eq=0; } sort(node+1,node+n+1,comp); FOR(i,1,n) { printf("%lld+%lld=[",node[i].a,node[i].b); if (node[i].eq==0) putchar('<'); else if (node[i].eq==1) putchar('='); else putchar('>'); printf("%lld]\n",node[i].sum); } puts(""); } return 0; }
J.X Property(待填坑)