The 10th Shandong Provincial Collegiate Programming Contest
A.队友写的
#include <iostream> using namespace std; typedef long long LL; int tran_int(string s1) { if (s1 == "Monday") return 0; if (s1 == "Tuesday") return 1; if (s1 == "Wednesday") return 2; if (s1 == "Thursday") return 3; if (s1 == "Friday") return 4; return 1; } string tran_string(LL a) { if (a == 0) return "Monday"; if (a == 1) return "Tuesday"; if (a == 2) return "Wednesday"; if (a == 3) return "Thursday"; return "Friday"; } int main() { int t; cin >>t; LL now1; LL now2; LL y1,m1,d1; string day; LL int_day; LL y2,m2,d2; while (t--) { cin >>y1>>m1>>d1>>day; cin >>y2>>m2>>d2; now1 = 360 *y1 +30*m1 +d1 -31; now2 = 360*y2 +30*m2 +d2 -31; //cout<<now2-now1<<endl; int_day = tran_int(day); int_day = ((int_day + now2-now1)%5 +5)%5; cout<<tran_string(int_day)<<endl; } return 0; }
B.队友写的
#include <iostream> #include <stdio.h> #include <string.h> using namespace std; typedef long long LL; const int mod = 998244353; int n,m,k; char s1[105]; char s2[105]; LL dp[105][105]; LL cn[105][105]; int main() { for (int i=0; i<=103; i++) { for (int j=0; j<=i ;j++) { if (j == 0) cn[i][j] = 1; else if (j == i) cn[i][j] = 1; else { cn[i][j] = cn[i-1][j-1] + cn[i-1][j]; if (cn[i][j] >= mod) cn[i][j] -= mod; } //cout<<cn[i][j]<<' '; } //cout<<endl; } int t; cin >>t; while (t--) { cin >>n >>k >>m; scanf("%s",s1); scanf("%s",s2); memset(dp,0,sizeof(dp)); int distan = 0; for (int i=0;i <n; i++) { if (s1[i] != s2[i]) distan ++; } dp[0][distan] = 1; int c1; for (int i=1; i<=k; i++) { for (int j =0; j<= n; j++) { c1 = 0; if (c1 <m-(n-j)) c1 = m-(n-j); for (; c1<= j && c1 <= m;c1++) { //c1 m-c1 dp[i][j - c1 + m - c1] = (dp[i][j - c1 + m - c1] + (((dp[i-1][j] * cn[j][c1])%mod) * cn[n-j][m-c1])%mod)%mod; //cout<<i-1<<' '<<j<<' '<<c1<<' '<< i<<' '<< j - c1 + m - c1<<" "<<dp[i][j - c1 + m - c1]<<endl; } } //for (int k1 =0; k1<= n; k1++) // cout<<i<<' '<<k1<<' '<<dp[i][k1]<<endl; } cout<<dp[k][0]<<endl; } return 0; } /* 3 3 2 1 001 100 3 1 2 001 100 3 3 2 001 100 */
C.队友写的
#include <iostream> #include <stdio.h> using namespace std; typedef long long LL; char an[112345]; LL cn[112345][2]; LL absll(LL a) { if (a <0) return -a; return a; } int main() { int t; cin >>t; while (t--) { LL now_x = 0; LL now_y =0; int n,k; cin >> n>>k; scanf("%s",an); LL now_max = 0; for (int i=0; i<n; i++) { if (an[i] == 'U') now_y++; if (an[i] == 'D') now_y--; if (an[i] == 'R') now_x++; if (an[i] == 'L') now_x--; cn[i][0] = now_x; cn[i][1] = now_y; } //cout<<cn[n-1][0] <<' '<<cn[n-1][1]<<endl; for (int i=0; i<n; i++) { now_max = max(now_max,absll(cn[i][0])+absll(cn[i][1])); //cout<<cn[i][0] <<' '<<cn[i][1]<<endl; cn[i][0] += (k-1) *cn[n-1][0]; cn[i][1] += (k-1) *cn[n-1][1]; now_max = max(now_max,absll(cn[i][0])+absll(cn[i][1])); //cout<<cn[i][0] <<' '<<cn[i][1]<<endl; } cout<<now_max<<endl; } ;; return 0; } /* 2 3 3 RUL 1 1000000000 D */
D.队友写的
#include <iostream> #include<cstring> #include<cstdio> using namespace std; char s[100005]; int main() { int T,N,M,n; cin>>T; while(T--) { cin>>n; scanf("%s",s); cin>>N>>M; int u,v; for(int i=0;i<M;i++) { scanf("%d%d",&u,&v); } if(s[(M-(N-1))%n]=='1') { printf("2\n"); } else { printf("1\n"); } } return 0; }
E.假设盒子大小为0,最终答案都是N,但是由于盒子容量的原因,相邻的同种颜色的盒子会对盒子容量大于一定值的情况产生负贡献。
准确的来说,若两颜色相同的盒子之间有x个不同种颜色的盒子且中间没有与这两盒子颜色相同的盒子,那会对最终所有大于x容量的盒子产生-1的贡献。
问题就简化为了区间颜色数量的题目,由于颜色数量为1e5,不能采用线段树状压,直接玩莫队就可以了。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 1e5 + 10; int N,M; struct Query{ int l,r,p; Query(){} Query(int l,int r):l(l),r(r){} }query[maxn]; int la[maxn]; int a[maxn]; bool cmp(Query a,Query b){ if(a.p != b.p) return a.p < b.p; return a.r < b.r; } int num[maxn]; int cnt; int sum; int pre[maxn]; int unit; void add(int p){ num[a[p]]++; if(num[a[p]] == 1) sum++; } void del(int p){ num[a[p]]--; if(num[a[p]] == 0) sum--; } void work(){ int L = 1,R = 0; sum = 0; for(int i = 1; i <= cnt; i ++){ while(R < query[i].r){ R++; add(R); } while(R > query[i].r){ del(R); R--; } while(L < query[i].l){ del(L); L++; } while(L > query[i].l){ L--; add(L); } pre[sum]++; } } int main() { int T; scanf("%d",&T); while(T--){ Sca(N); for(int i = 1; i <= N ; i ++) num[i] = la[i] = pre[i] = 0; cnt = 0; unit = (int)sqrt(N); for(int i = 1; i <= N ; i ++){ scanf("%d",&a[i]); if(la[a[i]]){ query[++cnt] = Query(la[a[i]] + 1,i); query[cnt].p = query[cnt].l / unit; } la[a[i]] = i; } sort(query + 1,query + 1 + cnt,cmp); work(); for(int i = 1; i <= N; i ++) pre[i] += pre[i - 1]; for(int i = 1; i <= N ; i ++){ printf("%d",N - pre[i]); if(i == N) puts(""); else printf(" "); } } return 0; }
F.贪心的发现最终到达的位置最优情况是所有盒子都变成sum / N,多的要不扔掉要不补少的,少的一定够,所以只要扔多的就可以了。
#include <iostream> #include <cstdio> #include <cmath> #include <cstdlib> #define LL long long using namespace std; const int maxn = 1e5 + 10; LL a[maxn]; int main() { int T; scanf("%d",&T); int N; while(T--){ scanf("%d",&N); LL sum = 0; for(int i = 1; i <= N ; i ++){ scanf("%lld",&a[i]); sum += a[i]; } LL p = sum / N; LL ans = 0; for(int i = 1; i <= N; i ++){ if(a[i] > p) ans += a[i] - p; } printf("%lld\n",ans); } return 0; }
H.把所有线段按照左端点排序,优先队列维护堆内终点的最小值。
从左往右扫描,若经过左端点则将该线段的右端点入堆。同时每次扫描到一个点都从堆中选取一个右端点最偏左的线段计入贡献。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 1e5 + 10; int N,M; PII line[maxn]; bool cmp(PII a,PII b){ if(a.fi == b.fi) return a.se < b.se; return a.fi < b.fi; } int main() { int T; scanf("%d",&T); while(T--){ Sca(N); for(int i = 1; i <= N ; i ++){ scanf("%d%d",&line[i].fi,&line[i].se); } N++; line[N] = mp(1e9 + 1e8,1); sort(line + 1,line + 1 + N,cmp); int now = 0; int p = 0; int ans = 0; priority_queue<int,vector<int>,greater<int> >Q; for(int i = 1; i <= N; i ++){ if(line[i].fi == now){ Q.push(line[i].se); }else if(line[i].fi > now){ for(int j = now; j < line[i].fi && !Q.empty(); j ++){ while(!Q.empty() && Q.top() < j) Q.pop(); if(!Q.empty()){ ans++; Q.pop(); } } now = line[i].fi; Q.push(line[i].se); } } printf("%d\n",ans); } return 0; }
J.题目要求最长路且不能走相同的路,发现整张图去掉一条路径就会变成一条欧拉路径。
那肯定是找一条最短路去掉,然后总贡献减去这条最短路的长度就是最终答案。
路径的输出就将最短路上的路径全部打上标记,去掉这些边之后直接欧拉路径即可。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 2e5 + 10; int id[303][303]; pair<int,int>Pos[maxn]; int N; struct Edge{ int to,next; bool vis; LL dis; }edge[maxn * 10]; int head[maxn],tot; LL dis[maxn]; int pre[maxn]; void init(){ for(int i = 0 ; i <= N; i ++) head[i] = -1; tot = 0; } void add(int u,int v,LL w){ edge[tot].to = v; edge[tot].next = head[u]; edge[tot].dis = w; edge[tot].vis = 0; head[u] = tot++; } struct node{ int pos; LL p; node(){} node(int pos,LL p):pos(pos),p(p){} friend bool operator < (node a,node b){ return a.p > b.p; } }; LL Dijkstra(int s,int t){ for(int i = 0 ; i <= N; i ++) dis[i] = 1e18; dis[s] = 0; priority_queue<node>Q; Q.push(node(s,0)); while(!Q.empty()){ node u = Q.top(); Q.pop(); if(u.p > dis[u.pos]) continue; for(int i = head[u.pos]; ~i ; i = edge[i].next){ int v = edge[i].to; LL w = edge[i].dis; if(dis[v] > u.p + w){ dis[v] = u.p + w; pre[v] = i; Q.push(node(v,dis[v])); } } } return dis[t]; } void Find(int t){ if(pre[t] == -1) return; if(t == id[1][1]) return; edge[pre[t]].vis = 1; edge[pre[t] ^ 1].vis = 1; Find(edge[pre[t] ^ 1].to); } vector<pair<int,int> > ans; void dfs(int t){ for(int i = head[t]; ~i ; i = edge[i].next){ if(edge[i].vis || edge[i ^ 1].vis) continue; int v = edge[i].to; edge[i].vis = edge[i ^ 1].vis = 1; dfs(v); } ans.pb(Pos[t]); } int main() { int T; scanf("%d",&T); int n; int cnt = 0; for(int i = 1; i <= 300; i ++){ for(int j = 1; j <= i; j ++){ id[i][j] = ++cnt; Pos[cnt] = mp(i,j); } } while(T--){ scanf("%d",&n); N = id[n][n]; for(int i = 0 ; i <= N ; i ++) pre[i] = -1; init(); ans.clear(); LL sum = 0; for(int i = 1; i <= n - 1; i ++){ for(int j = 1; j <= i ; j ++){ LL x; scanf("%lld",&x); add(id[i][j],id[i + 1][j],x); add(id[i + 1][j],id[i][j],x); sum += x; } } for(int i = 1; i <= n - 1; i ++){ for(int j = 1; j <= i ; j ++){ LL x; scanf("%lld",&x); add(id[i][j],id[i + 1][j + 1],x); add(id[i + 1][j + 1],id[i][j],x); sum += x; } } for(int i = 1; i <= n - 1; i ++){ for(int j = 1; j <= i; j ++){ LL x; scanf("%lld",&x); add(id[i + 1][j],id[i + 1][j + 1],x); add(id[i + 1][j + 1],id[i + 1][j],x); sum += x; } } LL d = Dijkstra(id[1][1],id[n][n]); sum -= d; Prl(sum); Find(id[n][n]); dfs(id[1][1]); printf("%d\n",ans.size()); for(int i = ans.size() - 1; i >= 0 ; i --){ printf("%d %d",ans[i].fi,ans[i].se); if(i) printf(" "); else puts(""); } } return 0; } /* 3 2 3 2 4 2 1 1 1 3 100 100 100 1 100 1 100 100 100 */
K.先打表发现a,k必定为偶数,然后推式子,具体推法是队友推的
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; LL mod; const int maxn = 1e5 + 10; int N,M; LL a,p; LL quick(LL b,LL k){ LL ans = 1; while(k){ if(k & 1)ans = (ans *b) % mod; b= (b * b) % mod; k >>= 1; } return ans; } LL cul(LL A,LL P){ LL ans = 0; for(int x = 1; x <= P; x ++){ if(quick(A,x) == quick(x,A)){ ans++; } } return ans; } int main() { int T; scanf("%d",&T); while(T--){ scanf("%lld%lld",&a,&p); if(a & 1){ puts("1"); continue; } mod = (1LL << p); LL ans = 0; if(a >= p){ LL l = p / 2, r = (1 << p)/2; ans += r-l; ans += cul(a,p); }else{ int o=0; while(1) { o++; if((o+1)*a>=p) break; } o++; ans+=((1<<p)/(1<<o))-p/(1<<(o)); ans+=cul(a,p); } Prl(ans); } return 0; }
L.所有点向必定比他大的连边,如果有超过一半必定比他大或者超过一半必定比他小的点就是0,否则为1
这种n只有100的图论题可以说是很友好了,一般来说要考虑拓扑排序dp,但是这个数据范围直接一个传递闭包上去就可以了。
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double eps = 1e-9; const int maxn = 110; int N,M; int MAP[maxn][maxn]; int main() { int T; scanf("%d",&T); while(T--){ scanf("%d%d",&N,&M); for(int i = 1; i <= N ; i++) for(int j = 1; j <= N ;j ++) MAP[i][j] = 0; for(int i = 1; i <= M ; i ++){ int u,v; Sca2(u,v); MAP[u][v] = 1; } for(int k = 1; k <= N ; k ++){ for(int i = 1; i <= N; i ++){ for(int j = 1; j <= N ; j ++){ if(MAP[i][k] && MAP[k][j]) MAP[i][j] = 1; } } } bool flag = 1; for(int i = 1; i <= N && flag; i ++){ for(int j = i; j <= N && flag; j ++){ if(MAP[i][j] && MAP[j][i]) flag = 0; } } if(!flag){ for(int i = 1; i <= N ; i ++) printf("0"); puts(""); continue; } for(int i = 1; i <= N ; i ++){ int ind = 0,outd = 0; for(int j = 1; j <= N ; j ++){ if(MAP[i][j]) outd++; if(MAP[j][i]) ind++; } if(ind <= N / 2 && outd <= N / 2){ printf("1"); }else{ printf("0"); } } puts(""); } return 0; }
M.队友写的
#include <iostream> using namespace std; int main() { int t; cin >>t; while (t--) { int n,k; cin >>n >>k; while (k--) { n = (n+1)/2; if (n <= 1) break; } cout<<n<<endl; } return 0; }