AtCoder Beginner Contest 247 Solution更好的阅读体验戳此进入题面链接题面 Luogu 链接A - Move Right题面SolutionCodeB - Unique Nicknames题面SolutionCodeC - 1 2 1 3 1 2 1题面SolutionCodeD - Cylinder题面SolutionCodeE - Max Min题面SolutionCodeF - Cards题面SolutionCodeG - Dream Team题面SolutionCodeEx - Rearranging Problem题面SolutionCodeUPD
给定一个
语法题没营养。
xxxxxxxxxx52123
45678910
11using namespace std;12using namespace __gnu_pbds;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
23template< typename T = int >24inline T read(void);25
26int main(){27 printf("0");28 char c = getchar();29 for(int i = 1; i <= 4; ++i){30 while(c != '1' && c != '0')c = getchar();31 if(i != 4)printf("%c", c);32 c = getchar();33 }printf("\n");34 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);35 return 0;36}37
38template < typename T >39inline T read(void){40 T ret(0);41 short flag(1);42 char c = getchar();43 while(c != '-' && !isdigit(c))c = getchar();44 if(c == '-')flag = -1, c = getchar();45 while(isdigit(c)){46 ret *= 10;47 ret += int(c - '0');48 c = getchar();49 }50 ret *= flag;51 return ret;52}给定 Yes,反之输出 No。
(语法题没一遍过,身败名裂了)
开个 map 维护一下每个字符串的出现次数,如果一个人的姓和名出现次数都大于等于
xxxxxxxxxx57123
45678910
11using namespace std;12using namespace __gnu_pbds;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
23template< typename T = int >24inline T read(void);25
26unordered_map < string, int > name;27string fn[110], ln[110];28
29int main(){30 int N = read();31 for(int i = 1; i <= N; ++i){32 cin >> fn[i] >> ln[i];33 name[fn[i]]++, name[ln[i]]++;34 }35 for(int i = 1; i <= N; ++i)36 if((fn[i] == ln[i] && name[fn[i]] >= 3) || (fn[i] != ln[i] && name[fn[i]] >= 2 && name[ln[i]] >= 2))37 printf("No\n"), exit(0);38 printf("Yes\n");39 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);40 return 0;41}42
43template < typename T >44inline T read(void){45 T ret(0);46 short flag(1);47 char c = getchar();48 while(c != '-' && !isdigit(c))c = getchar();49 if(c == '-')flag = -1, c = getchar();50 while(isdigit(c)){51 ret *= 10;52 ret += int(c - '0');53 c = getchar();54 }55 ret *= flag;56 return ret;57}我们按如下方式定义序列
给定
也算是个语法题吧。。
从定义就能看出来这是递归定义的,于是我们也写个递归,
(如果把
xxxxxxxxxx55123
45678910
11using namespace std;12using namespace __gnu_pbds;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
23template< typename T = int >24inline T read(void);25
26void PrintAns(int n){27 if(n == 1)return printf("1 "), void();28 PrintAns(n - 1);29 printf("%d ", n);30 PrintAns(n - 1);31}32
33int main(){34 int N = read();35 PrintAns(N);36 printf("\n");37 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);38 return 0;39}40
41template < typename T >42inline T read(void){43 T ret(0);44 short flag(1);45 char c = getchar();46 while(c != '-' && !isdigit(c))c = getchar();47 if(c == '-')flag = -1, c = getchar();48 while(isdigit(c)){49 ret *= 10;50 ret += int(c - '0');51 c = getchar();52 }53 ret *= flag;54 return ret;55}存在一个队列,给定
1 x c,表示向队尾插入
2 c,表示从队头取出
大概也算是个语法题?
维护一个队列,里面元素是个 pair < int, int > 记录元素值和数量,{x, c},Split 的操作,然后对应维护一下
对于
xxxxxxxxxx64123
45678910
11using namespace std;12using namespace __gnu_pbds;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
23template< typename T = int >24inline T read(void);25
26queue < pair < int, int >/*value, cnt*/ > balls;27
28int main(){29 int N = read();30 while(N--){31 int opt = read();32 if(opt == 1){33 int x = read(), c = read();34 balls.push({x, c});35 }else{36 ll ans(0);37 int c = read();38 while(c > 0 && !balls.empty()){39 auto tp = balls.front();40 if(c >= tp.second)balls.pop(), c -= tp.second, ans += (ll)tp.first * tp.second;41 else ans += (ll)c * tp.first, balls.front().second -= c, c = 0;42 }printf("%lld\n", ans);43 }44 }45
46 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);47 return 0;48}49
50template < typename T >51inline T read(void){52 T ret(0);53 short flag(1);54 char c = getchar();55 while(c != '-' && !isdigit(c))c = getchar();56 if(c == '-')flag = -1, c = getchar();57 while(isdigit(c)){58 ret *= 10;59 ret += int(c - '0');60 c = getchar();61 }62 ret *= flag;63 return ret;64}给定数列
关于本题有一些较为显然的
首先我们考虑这段区间里一定不能包含在
所以这时候我们只需要对于每个划分出来的子区间考虑其中的合法区间即可,不难想到我们要找的区间合法当且仅当里面包含了至少一个
此时考虑如何维护这四个值,显然我们可以考虑把子区间再次进行分割,遍历三次,分别由
然后还有个点就是如果
xxxxxxxxxx93123
45678910
11using namespace std;12using namespace __gnu_pbds;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
23template< typename T = int >24inline T read(void);25
26int N, X, Y;27int a[210000];28int cnt0(0), cnt1(0), cnt_1(0), l(1), r(-1);29ll ans(0);30
31ll GetC(int n, int m){32 if(n == 1)return 1;33 if(!n || m > n)return 0;34 ll ret(1);35 for(int i = n; i >= n - m + 1; --i)ret *= i;36 for(int i = m; i >= 1; --i)ret /= i;37 return ret + n;38}39
40int main(){41 N = read(), X = read(), Y = read();42 for(int i = 1; i <= N + 1; ++i){43 a[i] = i <= N ? read() : INT_MAX;44 a[i] = a[i] == X && a[i] == Y ? -114514 : (a[i] == X ? 1 : (a[i] == Y ? -1 : (Y <= a[i] && a[i] <= X ? 0 : 114514)));45 if(a[i] != 114514){r = i; continue;}46 if(!~r){l = i + 1; continue;}47 ll cur(0);48 cur += GetC(r - l + 1, 2);49 int ll(l), rr(-1);50 for(int j = l; j <= r; ++j){51 if(a[j] != -1 && a[j] != -114514){rr = j; continue;}52 if(!~rr){ll = j + 1; continue;}53 cur -= GetC(rr - ll + 1, 2);54 ll = j + 1;55 }if(ll <= rr)cur -= GetC(rr - ll + 1, 2);56 ll = l, rr = -1;57 for(int j = l; j <= r; ++j){58 if(a[j] != 1 && a[j] != -114514){rr = j; continue;}59 if(!~rr){ll = j + 1; continue;}60 cur -= GetC(rr - ll + 1, 2);61 ll = j + 1;62 }if(ll <= rr)cur -= GetC(rr - ll + 1, 2);63 ll = l, rr = -1;64 for(int j = l; j <= r; ++j){65 if(!a[j]){rr = j; continue;}66 if(!~rr){ll = j + 1; continue;}67 cur += GetC(rr - ll + 1, 2);68 ll = j + 1;69 }if(ll <= rr)cur += GetC(rr - ll + 1, 2);70 ans += cur;71 l = i + 1;72 }73 printf("%lld\n", ans);74
75 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);76 return 0;77}78
79template < typename T >80inline T read(void){81 T ret(0);82 short flag(1);83 char c = getchar();84 while(c != '-' && !isdigit(c))c = getchar();85 if(c == '-')flag = -1, c = getchar();86 while(isdigit(c)){87 ret *= 10;88 ret += int(c - '0');89 c = getchar();90 }91 ret *= flag;92 return ret;93}然后因为我是完全按照这个思路实现的所以上面的可能非常丑,所以这里也贴一个 @Zpair 的优美实现。
xxxxxxxxxx1812using namespace std;3typedef long long ll;4int l1,l2,l3,l4,n,x,y;ll ans;5ll get(int x){return (ll)x*(x+1)/2;}6int main(){7 cin>>n>>x>>y;int v;8 for(int i=1;i<=n;++i){9 scanf("%d",&v);10 if(v>x||v<y){ans+=get(l1)-get(l2)-get(l3)+get(l4),l1=l2=l3=l4=0;continue;}11 if(v!=x&&v!=y)l1++,l2++,l3++,l4++;12 if(v==x&&v==y)l1++,ans+=-get(l2)-get(l3)+get(l4),l2=l3=l4=0;13 if(v==x&&v!=y)l1++,l3++,ans+=-get(l2)+get(l4),l2=l4=0;14 if(v!=x&&v==y)l1++,l2++,ans+=-get(l3)+get(l4),l3=l4=0;15 }16 ans+=get(l1)-get(l2)-get(l3)+get(l4);17 cout<<ans;18}给定
考虑卡片之间的联系,显然若一个数在同一张卡牌的正反面那么这张卡牌必须选择,否则无法凑齐一个排列,反之这个数一定会在两张卡牌中出现,且这两张卡牌一定至少有一张被选择,否则依然无法凑齐一个排列,这个很好理解。
于是我们考虑一些对于这种题的一般的套路,可以尝试建图,对于本题不难想到,我们将一张卡牌作为一个点,将这个点向卡牌上存在的数的另一次出现所在的卡牌连一条边。抽象地说,对于一个数所在的两张(或一张)卡牌位置
不难想到这样会形成多个环,每一个环代表着其中几张卡牌,同时这些卡牌上的数在环内一定每个数都出现了两遍,如排列
同时发现不同环的方案数,只跟环的长度有关,于是我们考虑令
于是考虑并查集维护好每个环的大小,
xxxxxxxxxx78123
45678910
11using namespace std;12using namespace __gnu_pbds;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template< typename T = int >26inline T read(void);27
28int N;29int P[210000], Q[210000];30int cnt[210000];31int pos[210000][2];32int f[210000];33bool vis[210000];34int ans(1);35
36class UnionFind{37private:38public:39 int fa[210000];40 int siz[210000];41 UnionFind(void){for(int i = 1; i <= 201000; ++i)fa[i] = i, siz[i] = 1;}42 int Find(int x){return x == fa[x] ? x : fa[x] = Find(fa[x]);}43 void Union(int origin, int son){44 if(Find(origin) == Find(son))return;45 siz[Find(origin)] += siz[Find(son)], fa[Find(son)] = Find(origin);46 }47}uf;48
49int main(){50 N = read();51 f[1] = 1, f[2] = 3;52 for(int i = 3; i <= N; ++i)f[i] = (ll)(f[i - 1] + f[i - 2]) % MOD;53 for(int i = 1; i <= N; ++i)P[i] = read(), pos[P[i]][cnt[P[i]]++] = i;54 for(int i = 1; i <= N; ++i)Q[i] = read(), pos[Q[i]][cnt[Q[i]]++] = i;55 for(int i = 1; i <= N; ++i)56 uf.Union(i, pos[P[i]][0] ^ pos[P[i]][1] ^ i),57 uf.Union(i, pos[Q[i]][0] ^ pos[Q[i]][1] ^ i);58 for(int i = 1; i <= N; ++i)if(uf.Find(i) == i)ans = (ll)ans * f[uf.siz[uf.Find(i)]] % MOD;59 printf("%d\n", ans);60 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);61 return 0;62}63
64template < typename T >65inline T read(void){66 T ret(0);67 short flag(1);68 char c = getchar();69 while(c != '-' && !isdigit(c))c = getchar();70 if(c == '-')flag = -1, c = getchar();71 while(isdigit(c)){72 ret *= 10;73 ret += int(c - '0');74 c = getchar();75 }76 ret *= flag;77 return ret;78}咕咕咕
似乎是个费用流,先暂时咕掉了,以后再做。
xxxxxxxxxx11//TODO分治NTT,跳!
等联赛考完如果考过了再来做吧。。
xxxxxxxxxx11//TODOupdate-2022_10_25 初稿