2018 Multi-University Training Contest 3
Posted hetui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018 Multi-University Training Contest 3相关的知识,希望对你有一定的参考价值。
1001:Problem A. Ascending Rating
首先可以通过单调栈维护出每个位置右边第一个大于自己的数所在的位置,记为rightmax[i],然后维护一个双端队列。双端队列里维护[L,L+m-1]中的最长上升子序列,首先队首很好维护,只要判断当前head的
rightmax[]是不是在范围了内就行。队尾每当出队一个元素,需要按rightmax[]递归入队一个上升子序列。
因为每个元素最多只能入队出对一次,所以维护过程是O(2n)
#include<cstdio> #include<cstdlib> #include<cstring> #include<deque> #include<queue> #include<stack> #include<algorithm> #define maxn 10000000+5 using namespace std; struct FastIO { static const int S = 200; int wpos; char wbuf[S]; FastIO() :wpos(0) {} inline int xchar() { static char buf[S]; static int len = 0, pos = 0; if (pos == len) pos = 0, len = fread(buf, 1, S, stdin); if (pos == len) exit(0); return buf[pos++]; } inline int read() { int s = 1, c = xchar(), x = 0; while (c <= 32) c = xchar(); if (c == ‘-‘) s = -1, c = xchar(); for (; ‘0‘ <= c && c <= ‘9‘; c = xchar()) x = x * 10 + c - ‘0‘; return x * s; } ~FastIO() { if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0; } }io; deque <int> qu; int a[maxn], nxt[maxn], st[maxn], sst[maxn]; int n, m, k, p, q, r, mod; long long ans1, ans2; void find(int now, int lim) { if (nxt[now] != -1 && nxt[now] < lim) find(nxt[now], lim); if (lim != now) qu.push_front(now); } void find2(int now,int lim){ if (nxt[now] != -1 && nxt[now] - lim + 1 <= m) find2(nxt[now], lim); qu.push_front(now); } int main() { int T, top, l, r; T = io.read(); // scanf("%d",&T); while (T--) { n = io.read(); m = io.read(); k = io.read(); p = io.read(); q = io.read(); r = io.read(); mod = io.read(); // scanf("%d%d%d%d%d%d%d",&n,&m,&k,&p,&q,&r,&mod); for (int i = 1; i <= k; i++) a[i] = io.read(); // for (int i = 1; i <= k; i++) scanf("%d", &a[i]); for (int i = k + 1; i <= n; i++) a[i] = ((long long)p*a[i - 1] + (long long)q*i + r) % mod; // memset(nxt,0,sizeof(int)*(n+1)); top = 0; ans1 = ans2 = 0; for (int i = 1; i <= n; i++) { while (top && a[st[top]] < a[i]) nxt[st[top]] = i, top--; st[++top] = i; } while (top) nxt[st[top]] = -1, top--; while (!qu.empty()) qu.pop_back(); qu.push_back(1); int x = 0; while (qu.front() <= n && !qu.empty()) { while (nxt[qu.back()]>0 && nxt[qu.back()] - qu.front() + 1 <= m) { qu.push_back(nxt[qu.back()]); } x = qu.front(); ans1 += a[qu.back()]^x; ans2 += qu.size()^x; qu.pop_front(); if (x == n - m + 1) break; if (!qu.empty()) { int now=x+1, lim = qu.front(), top2=0; if (lim != now) sst[++top2] = now; while (nxt[now] != -1 && nxt[now] < lim) { now = nxt[now]; if (lim != now) sst[++top2] = now; } while (top2) qu.push_front(sst[top2]),top2--; } else { int now = x + 1, lim = x+1, top2 = 0; sst[++top2] = now; while (nxt[now] != -1 && nxt[now] - lim + 1 <= m) { now = nxt[now]; sst[++top2] = now; } while (top2) qu.push_front(sst[top2]),top2--; } } printf("%lld %lld ", ans1, ans2); } return 0; }
1003: Problem C. Dynamic Graph Matching
1004:Problem D. Euler Function
打个表吧,很容易看出规律。大于6的数的欧拉函数一定是合数
欧拉函数是积性函数,而除了2,3,质数的欧拉函数是偶数,所以除了个别数,欧拉函数都是合数
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <stack> #include <math.h> #include <vector> using namespace std; //返回某个数的欧拉值 int t,n; int main(){ int i; scanf("%d",&t); while(t--){ scanf("%d",&n); if(n>2) printf("%d ",n+5); else if(n==1) puts("5"); else if(n==2) puts("7"); } return 0; }
结论题,首先按层将树分成两部分,如果有一部分异或和大于另外一部分,那么先手拿这部分就行了,如果相等,因为是异或所以取一个节点和放一个节点影响一样,所以一定是平局
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define maxn 100000+5 using namespace std; struct Edge{ int u,v,nxt; }e[maxn<<1]; int head[maxn],w[maxn]; int n,ind,sum,all; void addedge(int x,int y){ e[ind]=(Edge){x,y,head[x]},head[x]=ind++; e[ind]=(Edge){y,x,head[y]},head[y]=ind++; } void dfs(int x,int pa,int dep){ if(dep&1) sum^=w[x]; for(int i=head[x];i!=-1;i=e[i].nxt) if(e[i].v!=pa) dfs(e[i].v,x,dep+1); } int main(){ int T; scanf("%d",&T); while(T--){ memset(head,-1,sizeof(head)); scanf("%d",&n); ind=all=0; for(int i=1;i<=n;i++) scanf("%d",&w[i]),all^=w[i]; for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); addedge(x,y); } sum=0; dfs(1,0,1); if((all^sum)==sum) puts("D"); else puts("Q"); } return 0; }
1007: Problem G. Interstellar Travel
1008:Problem H. Monster Hunter
1009:Problem I. Random Sequence
很有意思的概率DP,官方题解很详细
设f[i][x][y][z]表示考虑前i个位置,a i =x,gcd(a i ,a i?1 )=y,gcd(a i ,a i?1 ,a i?2 )=z的期望,枚举a i+1 的值转移即可。
时间复杂度O(nmS),其中S表示(x,y,z)的状态数。显然合法状态中y∣x,z∣y,当m=100时S=1471。
#include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #include <string> #include <map> using namespace std; const long long mod=1e9+7; long long dp[2][110][110][110]; int ai[110],vi[110],biao[110][110],le[110],ri[110]; vector <int> fac[110]; int n,m; void init() { memset(dp,0,sizeof(dp)); for(int i=le[3];i<=ri[3];i++) { for(int j=le[2];j<=ri[2];j++) { for(int k=le[1];k<=ri[1];k++) dp[0][i][biao[i][j]][biao[k][biao[i][j]]]++; } } } int gcd(int a,int b) { if(b==0) return a; return gcd(b,a%b); } long long qp(long long p,long long q) { long long cnt=1; while(q>0) { if(q%2==1) cnt=(cnt*p)%mod; q/=2; p=(p*p)%mod; } return cnt%mod; } int main() { int i,j; for(i=1;i<=100;i++) { for(j=1;j<=100;j++) biao[i][j]=gcd(i,j); } for(i=1;i<=100;i++) { for(j=i;j<=100;j+=i) fac[j].push_back(i); } int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) { scanf("%d",&ai[i]); if(ai[i]==0) { le[i]=1; ri[i]=m; } else le[i]=ri[i]=ai[i]; } for(i=1;i<=m;i++) scanf("%d",&vi[i]); init(); int xx=0; //cout<<"1"<<endl; for(i=4;i<=n;i++) { int x,y,z; for(x=1;x<=m;x++) { for(vector<int>::iterator iy=fac[x].begin();iy!=fac[x].end();iy++) { y=*iy; for(vector<int>::iterator iz=fac[y].begin();iz!=fac[y].end();iz++) { z=*iz; // cout<<x<<" "<<y<<" "<<z<<endl; if(dp[xx][x][y][z]==0) continue; for(j=le[i];j<=ri[i];j++) { dp[xx^1][j][biao[j][x]][biao[j][y]]+=dp[xx][x][y][z]*vi[biao[j][z]]; dp[xx^1][j][biao[j][x]][biao[j][y]]%=mod; } dp[xx][x][y][z]=0; } } } xx^=1; } long long ans=0; int x,y,z; for(x=1;x<=m;x++) { for(vector<int>::iterator iy=fac[x].begin();iy!=fac[x].end();iy++) { y=*iy; for(vector<int>::iterator iz=fac[y].begin();iz!=fac[y].end();iz++) { z=*iz; // cout<<x<<" "<<y<<" "<<z<<endl; ans=(ans+dp[xx][x][y][z])%mod; } } } long long tmp=qp(m,mod-2); for(i=1;i<=n;i++) { if(ai[i]==0) ans=(ans*tmp)%mod; } printf("%lld ",ans); } return 0; }
画家算法,模拟一下即可。从下到上,从里到外,从左到右,一个一个的小立方体画就行了
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <stack> #include <math.h> #include <vector> using namespace std; const int MAX=200; int t,a,b,c; int mp[MAX][MAX]; int main(){ int i,j,p,cnt; int x,y; scanf("%d",&t); while(t--){ scanf("%d%d%d",&a,&b,&c); for(i=0;i<MAX;i++) for(j=0;j<MAX;j++) mp[i][j]=‘.‘; x=2*c+1,y=2*b; for(p=0;p<max(b+1,2);p++){ for(i=x;i>x-2*c-1;i-=2) for(j=y;j<y+2*a+1;j+=2) mp[i][j]=‘+‘; x+=2,y-=2; } x=1,y=2*b+1; for(p=0;p<=max(b+1,2);p++){ for(j=y;j<=y+2*a-1;j+=2) mp[x][j]=‘-‘; x+=2,y-=2; } x=2*b+1,y=0; for(p=0;p<c+1;p++){ for(j=1;j<2*a;j+=2) mp[x][j]=‘-‘; x+=2,y-=2; } x=2,y=2*b+2*a,cnt=2; for(p=0;p<max(b+1,2);p++){ for(i=x;i<x+2*c;i+=2) mp[i][y]=‘|‘; x+=2,y-=2; } x=2*b+2,y=0; for(i=x;i<x+2*c;i+=2) for(j=y;j<2*a;j+=2) mp[i][j]=‘|‘; x=2,y=2*b-1; for(p=0;p<b;p++){ for(j=y;j<y+2*a+2;j+=2) mp[x][j]=‘/‘; x+=2,y-=2; } x=2,y=2*b+2*a-1; for(p=0;p<b;p++){ for(i=x;i<x+2*c+2;i+=2) mp[i][y]=‘/‘; x+=2,y-=2; } for(i=1;i<1+2*b+2*c+1;i++){ for(j=0;j<2*b+2*a+1;j++) printf("%c",mp[i][j]); putchar(‘ ‘); } } return 0; }
以上是关于2018 Multi-University Training Contest 3的主要内容,如果未能解决你的问题,请参考以下文章
2018 Multi-University Training Contest 2
2018 Multi-University Training Contest 9
2018 Multi-University Training Contest 4
2018 Multi-University Training Contest 4