暑假集训7
A. One
用vector把out的及时删掉,然后就可以直接加位置了,STL真好用,不过它T了……

#include <bits/stdc++.h> using namespace std; int T, n; vector<int> a; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { T = read(); while(T--) { a.clear(); n = read(); for(int i=1; i<=n; i++) { a.push_back(i); } int sz = a.size(), p = 1, pos = 0; while(sz > 1) { pos += p-1; pos %= sz; //printf("pos = %d\n", pos); a.erase(a.begin()+pos); pos; p++; sz--; } printf("%d\n", a[0]); } return 0; }
看到约瑟夫问题这几个字时第一印象是绝对没见过,好吧,原来是我忘了,[概率和期望]里的卡牌游戏可能是一个比较相似的。
从最后一个留下的人开始考虑,不断把上一轮出局的人加回来,在这个过程中保证让最后留下的人站在队尾,就生成了一个“构造序列”。假设第n轮游戏(游戏结束后的下一轮)仍在继续,那么这一轮数1的人一定是1号(在当前时间的构造序列中的编号),tot记录总人数,kil记录当前轮数1的人的位置,同时也是上一局出局的人在上一局中的位置,因为前面的人出局了,所以下一局数1的人填到了上一局出局的人的位置上。
从第n局推到第n-1局,最后的赢家还在队尾,tot++,第n-1局出局的人就是他前面那个(这时只有两个人),加减抵消所以第n-1局出局的人还是kil,前面那半句没什么用,我们还需要继续往前推直到找到第一次出局的人(数1的人)在构造序列中的位置,因为第一次出局的人在“给出序列”中的位置一定是1,这就得到了“构造序列”和“给出序列”的对应关系,就可以知道在构造序列中的最后一个人(胜者)在给出序列中的编号。
我要求出在第i局(最后到第1局)中数1的人的位置,可以通过在这一局数i(出局的人,每一局的编号就是这一局不能被数到的数字)的位置来求,也就是再下一局中数1的人的位置,而下一局中数1的人的位置已知,所以问题就转化为:有tot个人,从x位置开始数1,数到i的人是kil,求x。
kil = (kil-i%tot+tot+1)%tot
大概就是r-l+1=len, l=r-len+1,其中这个len可能过分长了。

#include <bits/stdc++.h> using namespace std; int T, n; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { T = read(); while(T--) { n = read(); int kil = 1, tot = 1; for(int i=n-1; i>=1; i--) { tot++; kil = (kil-i%tot+tot+1)%tot; if(!kil) kil = tot; } printf("%d\n", n-kil+1); } return 0; }
B. 砖块
看起来很麻烦的样子不想做怎么办……那就来一个k=1的特判吧……考完才发现是大水题……后悔了。
记录左下脚的位置和当前的状态,过程挺暴力的。

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 107; const int N = 505; const ll mod = 1e9 + 7; const int inf = (1<<29); int dx[5] = {0, 0, 0, 1, -1}; int dy[5] = {0, 1, -1, 0, 0}; int T, k, b[104], a[2006][2006], n, ans, st; char s[104]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main()//k = 1 { T = read(); while(T--) { k = read(); scanf("%s", s+1); n = strlen(s+1); for(int i=1; i<=n; i++) { if(s[i] == 'E') b[i] = 1; else if(s[i] == 'W') b[i] = 2; else if(s[i] == 'N') b[i] = 3; else b[i] = 4; } memset(a, 0, sizeof(a)); int x = 1000, y = 1000; a[x][y] = 1; ans = 1; st = 1; for(int i=1; i<=n; i++) { if(b[i] == 3) { if(st == 1) { st = 2; x++; for(int j=x; j<x+k; j++) { a[j][y]++; //printf("a[%d][%d]++\n", j-100, y-100); ans = max(ans, a[j][y]); } //printf("st = %d %d %d\n", st, y-100, x-100); } else if(st == 2) { st = 1; x += k; a[x][y]++; //printf("a[%d][%d]++\n", x-100, y-100); ans = max(ans, a[x][y]); } else { x++; for(int j=y; j<y+k; j++) { a[x][j]++; //printf("a[%d][%d]++\n", x-100, j-100); ans = max(ans, a[x][j]); } } } else if(b[i] == 1) { if(st == 1) { st = 3; y++; for(int j=y; j<y+k; j++) { a[x][j]++; //printf("a[%d][%d]++\n", x-100, j-100); ans = max(ans, a[x][j]); } } else if(st == 2) { y++; for(int j=x; j<x+k; j++) { a[j][y]++; //printf("a[%d][%d]++\n", j-100, y-100); ans = max(ans, a[j][y]); } } else { st = 1; y += k; a[x][y]++; //printf("a[%d][%d]++\n", x-100, y-100); ans = max(ans, a[x][y]); } } else if(b[i] == 2) { if(st == 1) { st = 3; y -= k; for(int j=y; j<y+k; j++) { a[x][j]++; //printf("a[%d][%d]++\n", x-100, j-100); ans = max(ans, a[x][j]); } } else if(st == 2) { y--; for(int j=x; j<x+k; j++) { a[j][y]++; //printf("a[%d][%d]++\n", j-100, y-100); ans = max(ans, a[j][y]); } } else { st = 1; y--; a[x][y]++; //printf("a[%d][%d]++\n", x-100, y-100); ans = max(ans, a[x][y]); } } else { if(st == 1) { st = 2; x -= k; for(int j=x; j<x+k; j++) { a[j][y]++; //printf("a[%d][%d]++\n", j-100, y-100); ans = max(ans, a[j][y]); } } else if(st == 2) { x--; st = 1; a[x][y]++; //printf("a[%d][%d]++\n", x-100, y-100); ans = max(ans, a[x][y]); } else { x--; for(int j=y; j<y+k; j++) { a[x][j]++; //printf("a[%d][%d]++\n", x-100, j-100); ans = max(ans, a[x][j]); } } } } if(st == 1) { printf("%d\n", y-1000); printf("%d\n", x-1000); } else if(st == 2) { //printf("%d\n", y-1000); for(int i=x; i<x+k; i++) { printf("%d ", y-1000); } printf("\n"); for(int i=x; i<x+k; i++) { printf("%d ", i-1000); } printf("\n"); } else { for(int i=y; i<y+k; i++) { printf("%d ", i-1000); } printf("\n"); //printf("%d\n", x-1000); for(int i=y; i<y+k; i++) { printf("%d ", x-1000); } printf("\n"); } printf("%d\n", ans); } return 0; }
C. 数字
我只会把0去掉挨个乘*本来取模都是取的正好的,结果提交之前发现同一个数输出不同位不对应!?于是把它改大了一点……

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 24; const int N = 505; int k, T; ll ans, n; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { T = read(); while(T--) { scanf("%lld", &n); k = read(); if(k == 1) { ll mod = 10000; ans = 1; for(int i=1; i<=n; i++) { ans *= i; //printf("pre : %lld ", ans); while(ans % 10 == 0 && ans) ans /= 10; //printf("ans = %lld\n", ans); ans %= mod; //printf("%lld\n", ans); } ans %= 10; printf("%lld\n", ans); } if(k == 2) { ll mod = 10000; ans = 1; for(int i=1; i<=n; i++) { ans *= i; while(ans % 10 == 0 && ans) ans /= 10; ans %= mod; } ans %= 100; if(ans / 10 == 0) printf("0"); printf("%lld\n", ans); } if(k == 3) { ll mod = 10000; ans = 1; for(int i=1; i<=n; i++) { ans *= i; while(ans % 10 == 0 && ans) ans /= 10; ans %= mod; } ans %= 1000; if(ans / 100 == 0) printf("0"); if(ans / 10 == 0) printf("0"); printf("%lld\n", ans); } } return 0; }
https://www.cnblogs.com/My-tiantian/p/11626918.html
但是后来并没有用到crt来解同余方程(x % 8 = 0 && x % 125 = (n!/10^max) % 125),在1000之内枚举同时满足两个条件的数就可以了。n! / 10^max 里2的剩余数量很多,默认它%8=0,但其实在5!及之前%8!=0,所以特判是直接暴力找了。
c5 = max,是n!里10的最多次数(也就是5的),每次从n里除去一个5^i就是根据5的出现次数分层筛出,不管5出现几次只算1个,因为前面5^1~5^(i-1)已经去掉了其它的5.

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1005; const int base = 10000; const int block = 4; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } char c[maxn]; struct big { int a[maxn]; big() {clear(); } void clear() {memset(a, 0, sizeof(a)); } void in() { clear(); scanf("%s", c+1); int len = strlen(c+1); a[0] = (len + block - 1) / block; for(int i=1; i<=len; i++) { int j = (len-i+block)/block; a[j] = a[j] * 10 + (c[i]^48); } while(a[a[0]] == 0 && a[0]) a[0]--; } friend big operator / (big a, const int x) { int res = 0; for(int i=a.a[0]; i>0; i--) { res = res * base + a.a[i]; a.a[i] = res / x; res %= x; } while(!a.a[a.a[0]] && a.a[0]) a.a[0]--; return a; } int operator % (const int x) const { int res = 0; for(int i=a[0]; i>0; i--) { res = res * base + a[i]; res %= x; } return res; } }a; int qpow(int a, int b, int mod) { int ans = 1; while(b) { if(b & 1) ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } int get_f(big now, int p, int pk) { if(now.a[0] == 0) return 1; int res = 1, ls = now % pk, num; for(int i=2; i<=ls; i++) { if(i % p) res = res * i % pk; } num = res; for(int i=ls+1; i<pk; i++) { if(i % p) res = res * i % pk; } return get_f(now/p, p, pk) * qpow(res, (now/pk)%100, pk)%pk*num%pk; } int getc5() { int c5 = 0; big b; b = a; while(b.a[0]) { c5 = (c5 + (b / 5) % 100) % 100; b = b / 5; } return c5; } int work() { if(a.a[0] == 1 && a.a[0] <= 5) { int n = a.a[1], cnt = 0; ll ans = 1; for(int i=2; i<=n; i++) { int now = i; while(now % 5 == 0) now /= 5, cnt++; ans = ans * now; while(cnt && ans % 2 == 0) ans = ans / 2, cnt--; ans %= 100000; } return ans % 1000; } int c5 = getc5(); int res = get_f(a, 5, 125); //求2^m在mod125,63是2%125意义下的逆元,100是125的欧拉函数(125-125*1/5),指数优化 int mod125 = res * qpow(63, c5 % 100, 125) % 125; for(int i=8; i<=1000; i+=8) { if(i % 125 == mod125) return i; } return 0; } int main() { int t = read(); while(t--) { a.in(); int k = read(); if(k == 1) printf("%d\n", work()%10); if(k == 2) printf("%02d\n", work()%100); if(k == 3) printf("%03d\n", work()%1000); } return 0; }
D. 甜圈
我用线段树标记了一下区间合法的数目,区间进行到的步骤(颜色),区间进度是否一致,还有一个lazy,结果它T了……当我听说比较高级的暴力都拿到了70 eps的时候……啊不过我不后悔搞了棵树,因为我不知道怎么暴力。

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5 + 4; const int N = 505; const ll mod = 1e9 + 7; const int inf = (1<<29); int n, k, m, ans; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct node { int sum, col, lazy, only; }t[maxn<<2]; void pushup(int x) { t[x].sum = t[x<<1].sum + t[x<<1|1].sum; //printf("pushup: t[%d].sum = %d\n", x, t[x].sum); if(t[x<<1].col == t[x<<1|1].col && t[x<<1].only && t[x<<1|1].only) { t[x].only = 1; t[x].col = t[x<<1].col; } else { t[x].col = -1; t[x].only = 0; //printf("t[%d].only = 0\n", x); } } void build(int x, int l, int r) { if(l == r) { t[x].sum = 1; t[x].only = 1; return; } int mid = (l + r) >> 1; build(x<<1, l, mid); build(x<<1|1, mid+1, r); pushup(x); } void pushdown(int x, int l, int r) { int ls = x<<1, rs = x<<1|1; if(t[x].lazy == 1) { t[ls].col = t[rs].col = t[x].col; //printf("t[%d].col = t[%d].col = %d\n", ls, rs, t[ls].col); t[ls].lazy = t[rs].lazy = 1; } else if(t[x].lazy == -1) { t[ls].col = t[rs].col = -1; t[ls].lazy = t[rs].lazy = -1; t[ls].sum = t[rs].sum = 0; //printf("t[%d] and t[%d] is cleaned\n", ls, rs); } t[x].lazy = 0; } void update(int x, int l, int r, int L, int R, int col) { //printf("update(%d, %d, %d, %d, %d, %d)\n", x, l, r, L, R, col); if(L <= l && r <= R) { if(t[x].only) { if(t[x].col == col-1) { t[x].col = col; t[x].lazy = 1; //printf("t[%d].col = %d\n", x, t[x].col); return; } else { t[x].col = -1; t[x].sum = 0; //printf("t[%d] is cleaned\n", x); t[x].lazy = -1; return; } } } if(t[x].lazy) pushdown(x, l, r); int mid = (l + r) >> 1; if(L <= mid) update(x<<1, l, mid, L, R, col); if(R > mid) update(x<<1|1, mid+1, r, L, R, col); pushup(x); } int main() { n = read(); k = read(); build(1, 1, n); m = read(); while(m--) { int l = read(), r = read(), col = read(); update(1, 1, n, l, r, col); } update(1, 1, n, 1, n, k+1); /*for(int i=1; i<=9; i++) { printf("t[%d].sum = %d\n", i, t[i].sum); }*/ ans = t[1].sum; printf("%d\n", ans); return 0; }
在区间进行到的步骤不一致的情况下还要强行区间修改随时记录合法数量是一种非常耗时的操作,稍微有一点水平的数据都可能把这种伪区间修改变成单点修改。
一个区间如果只记录了一种操作就一定要找到操作一致的区间才能修改,我记了个lazy标记搞了半天其实只是删除了不合法的情况,而且还可能删除很多遍,假的lazy其实并不记录区间的颜色只是用来修改合法数量的多少,因为这种记录方法下颜色也不能下传,比如x的区间先覆盖2,再覆盖3,然后2没了,x有覆盖过1的孩子,但是用1和3一合并就成了非法情况。所以它和暴力的单点修改没什么差别了……
为了让颜色可以传递,有一种更好的记录方式:
记录起点和终点。这样pushdown时大区间的起点拼上子区间终点就可以完成传递的操作,而询问只有一次,已经确定询问是整体,就完全没有必要把它也搬到线段树上来维护了,最后dfs一下就好了。

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5 + 4; const int N = 505; const ll mod = 1e9 + 7; const int inf = (1<<29); int n, k, m, ans; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct node { int st, ed; }t[maxn<<2]; void build(int x, int l, int r) { if(l == r) { t[x].st = t[x].ed = 0; return; } int mid = (l + r) >> 1; build(x<<1, l, mid); build(x<<1|1, mid+1, r); } inline void add(int x, int l, int r, int st, int ed) { if(t[x].st == 0 && l != r) { t[x].st = st, t[x].ed = ed; } else { if(t[x].ed == st-1) t[x].ed = ed; else t[x].st = -1; } } inline void pushdown(int x, int l, int r) { int ls = x<<1, rs = x<<1|1, mid = (l + r) >> 1; add(ls, l, mid, t[x].st, t[x].ed); add(rs, mid+1, r, t[x].st, t[x].ed); t[x].st = t[x].ed = 0; } void update(int x, int l, int r, int L, int R, int col) { if(L <= l && r <= R) { add(x, l, r, col, col); return; } if(t[x].st) pushdown(x, l, r); int mid = (l + r) >> 1; if(L <= mid) update(x<<1, l, mid, L, R, col); if(R > mid) update(x<<1|1, mid+1, r, L, R, col); } void dfs(int x, int l, int r) { if(l == r) { //printf("cmp : %d %d %d\n", t[x].st, t[x].ed, k); if(t[x].st != -1 && t[x].ed == k) { ans++; //printf("ans = %d\n", ans); } return; } if(t[x].st) pushdown(x, l, r); int mid = (l + r) >> 1; dfs(x<<1, l, mid); dfs(x<<1|1, mid+1, r); } int main() { n = read(); k = read(); build(1, 1, n); m = read(); while(m--) { int l = read(), r = read(), col = read(); update(1, 1, n, l, r, col); } //update(1, 1, n, 1, n, k+1); /*for(int i=1; i<=9; i++) { printf("t[%d].st = %d t[%d].ed = %d\n", i, t[i].st, i, t[i].ed); }*/ //ans = t[1].sum; //printf("%d\n", ans); dfs(1, 1, n); printf("%d\n", ans); return 0; }
还有一种哈希的做法:把每个点看成一个字符串,在一堆操作之后只有一种字符串是合法的(1234...k),区间修改hash的操作用线段树来实现。
忽然连想到了[平衡树基础Splay和Treap]专题里的火星人prefix,但是平衡树上的hash还是有点不一样,它是把树上的节点的hash值拼接起来,但是这道题的线段树上每个点的hash都是独立的只属于自己。
跳回来:fac是指初始值和系数想乘,add是往上加的内容相当于lazy,注意pushdown乘法在前,还有细节是比较标准的设定,一般字符串哈希时hash的初始值都为0,在线段树上的hash初始值却变成了1,因为线段树建树时初始化base的倍数是1,而且必须不能为0,否则在修改时对fac做的操作相当于无效,0*base=0.也是因为比较标准初始化为1不是像求阶乘一样的原理(既是初始化也是最终的结果),所以循环不能从2开始!

#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const ull base = 131; const int maxn = 2e5 + 4; const int N = 505; const ll mod = 1e9 + 7; const int inf = (1<<29); int n, k, m; ull strf=1; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } struct node { ull fac, add; }t[maxn<<2]; void build(int x, int l, int r) { t[x].fac = 1; if(l == r) return; int mid = (l + r) >> 1; build(x<<1, l, mid); build(x<<1|1, mid+1, r); } inline void pushdown(int x) { int ls = x<<1, rs = x<<1|1; if(t[x].fac != 1) { t[ls].fac *= t[x].fac; t[rs].fac *= t[x].fac; t[ls].add *= t[x].fac; t[rs].add *= t[x].fac; t[x].fac = 1; } if(t[x].add) { t[ls].add += t[x].add; t[rs].add += t[x].add; t[x].add = 0; } } void update(int x, int l, int r, int L, int R, int col) { if(L <= l && r <= R) { t[x].add *= base; t[x].fac *= base; t[x].add += col; return; } pushdown(x); int mid = (l + r) >> 1; if(L <= mid) update(x<<1, l, mid, L, R, col); if(R > mid) update(x<<1|1, mid+1, r, L, R, col); } int query(int x, int l, int r) { if(l == r) { if(t[x].fac + t[x].add == strf) return 1; return 0; } pushdown(x); int mid = (l + r) >> 1; return query(x<<1, l, mid) + query(x<<1|1, mid+1, r); } int main() { n = read(); k = read(); for(int i=1; i<=k; i++) strf = strf * base + i; //printf("strf = %lld\n", strf); build(1, 1, n); m = read(); while(m--) { int l = read(), r = read(), col = read(); update(1, 1, n, l, r, col); } printf("%d\n", query(1, 1, n)); return 0; }
有没有发现自从Cat借鉴了一定数目的Chen_jr大佬的题解之后,连线段树的格式都改了……
还有一种方法是分块%%%Chen_jr,思路和第一种线段树的写法差不多,记录每个点的颜色大概体现了暴力的部分,再次认证Cat的第一版就是纯属暴力,除了麻烦啥都没有……

#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const ull base = 131; const int maxn = 2e5 + 4; const int N = 505; const ll mod = 1e9 + 7; const int inf = (1<<29); int block[maxn], l[maxn], r[maxn], now[maxn], n, k, len, m, ans; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } void pushdown(int blo) { if(l[blo]) { int pl = (blo-1)*len+1, pr = min(blo*len, n); for(int i=pl; i<=pr; i++) { if(now[i]+1 == l[blo]) now[i] = r[blo]; else now[i] = -1; } l[blo] = r[blo] = 0; } } void modify(int ll, int rr, int x) { for(int i=ll; i<=rr; i++) { if(now[i]+1 == x) now[i]++; else now[i] = -1; } } void solve(int ll, int rr, int x) { pushdown(block[ll]); pushdown(block[rr]); if(block[ll] == block[rr]) { modify(ll, rr, x); return; } modify(ll, min(block[ll]*len, n), x); modify((block[rr]-1)*len+1, rr, x); for(int i=block[ll]+1; i<block[rr]; i++) { if(l[i] != -1) { if(l[i] == 0) l[i] = r[i] = x; else { if(r[i]+1==x) r[i]++; else l[i] = r[i] = -1; } } } } int main() { n = read(); k = read(); len = sqrt(n); for(int i=1; i<=n; i++) { block[i] = (i+len-1)/len; } m = read(); while(m--) { int ll = read(), rr = read(), x = read(); solve(ll, rr, x); } for(int i=1; i<=block[n]; i++) pushdown(i); for(int i=1; i<=n; i++) { if(now[i] == k) ans++; } printf("%d\n", ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!