(点击题目即可查看原题)
题意:给出起点和终点,每次移动只能从 (a,b)移动至(a+x,b+y) , (a+x,b-y) , (a-x,b+y) , (a-x,b-y) 四个位置,问能否从终点走到起点
思路:先计算出起点和终点的横纵坐标之差 X,Y, 首先必须满足 X%x == 0 && Y % y == 0 ,这样才可以走到和终点一样的位置,后计算 X/x . Y/y ,我们注意到如果 X/x != Y/y 那么就可能无法用到达,不过,我们可以在两次运动过程中只走X方向或者Y方向,也就是如果 abs( X/x - Y/y ) % 2 == 0 ,那么也是可以到达的;此外的情况都是无法到达的。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x,y) cout<<"["<<x<<","<<y<<"] " //#define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 1e6 + 3; const int Max = 1e5 + 10; int s_x, s_y, e_x, e_y; int x, y; int main() { #ifdef LOCAL freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); #endif while (scanf("%d%d%d%d", &s_x, &s_y, &e_x, &e_y) != EOF) { scanf("%d%d", &x, &y); if (abs(s_x - e_x) % x == 0 && abs(s_y - e_y) % y == 0 && abs(abs(s_x - e_x) / x - abs(s_y - e_y) / y) % 2 == 0) { printf("YES\n"); } else { printf("NO\n"); } } return 0; }
题意:给出n个数a[1] ~ a[n] ,求使得 a[i] * a[j] * a[k] 最小的组合 (i,j,k) 有多少个,其中 i , j , k 互不相等。
思路:摆明了让你求最小的三个值的个数,求出最小值,,次小值的,,第三小值的个数,然后根据以下规律凑成组合并输出个数,emmm,组合数
1)最小的有三个以上,那么三个均有最小的组成
2)如果最小的只有两个,那么最小的肯定要选,所以由两个最小和一个次小组成
3)最小的只有一个,次小的有两个以上,那么由一个最小和两个次小组成
4)最小和次小都只有一个,那么由最小,次小,第三小各选一个组成
输出对应的组合数即可(博主用自己的组合数板子写了第一发,结果范围不够,WA了,不过这个地方不需要用组合数板子来写,因为计算次数最多4次,直接算就好)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<stdio.h> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x,y) cout<<"["<<x<<","<<y<<"] " //#define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; const int Max = 1e5 + 10; int n; int a[Max]; map<int, int>mp; //记录每个数字出现的次数 int main() { #ifdef LOCAL freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); #endif while (scanf("%d", &n) != EOF) { mp.clear(); for (int i = 1;i <= n;i++) { scanf("%d", a + i), mp[a[i]]++; } sort(a + 1, a + 1 + n); int tot = unique(a + 1, a + 1 + n) - a - 1; //排序并去重,使得a[1]~a[3]对应最小的三个数 if (mp[a[1]] >= 3) //最小的有三个以上,那么三个均有最小的组成 { printf("%d\n",mp[a[1]] * (mp[a[1]] -1 ) * (mp[a[1]] -2) / 6); } else if (mp[a[1]] == 2) //如果最小的只有两个,那么最小的肯定要选,所有由两个最小和一个次小组成 { printf("%d\n", mp[a[2]]); } else if (mp[a[1]] == 1 && mp[a[2]] >= 2) //最小的只有一个,次小的有两个以上,那么有一个最小和两个次小组成 { printf("%d\n", mp[a[2]] * (mp[a[2]] - 1) / 2); } else //最小和次小都只有一个,那么最小,次小,第三小各选一个 { printf("%d\n",mp[a[3]]); } } return 0; }
题意:给出两个数n,s,问在 [1,n] 范围内有多少个数 满足 x 和 x 的各个位上的数之和 大于s ( x 属于 [1,n])
思路:打表找规律,发现从某一个数开始,后面的数都是满足条件的,那么就简单了,二分第一个满足的数,其后的数就都满足条件了
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<stdio.h> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x, y) cout<<"["<<x<<","<<y<<"] " #define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; const int Max = 1e5 + 10; ll n, m; int main() { #ifdef LOCAL //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); #endif while (scanf("%lld%lld", &n, &m) != EOF) { ll l = 1, r = n; while (l <= r) { ll sum = 0; ll mid = (l + r) >> 1; ll k = mid; while (k) { sum += k % 10; k /= 10; } if (abs(mid - sum) < m) { l = mid + 1; } else { r = mid - 1; } } printf("%lld\n", n - l + 1); } return 0; }
818A Diplomas and Certificates
题意:有n个人,需要为他们分两种奖品,其中一种奖品的数量必须是另一种奖品数量的k倍,每个人只能分到一个奖品,并且有奖品的人数不得超过n/2个,输出两种奖品的数量和没有得奖的人数
思路:一个简单的公式 x + k * x <= n/2 ,得到的x向下取整,输出 x , k * x , n - (k+1)*x 就OK了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<stdio.h> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x,y) cout<<"["<<x<<","<<y<<"] " //#define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; const int Max = 1e5 + 10; ll n, k; int main() { #ifdef LOCAL freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); #endif while (scanf("%lld%lld", &n, &k) != EOF) { ll x = (n/2) / (k + 1); printf("%lld %lld %lld\n", x, k*x, n - (k + 1)*x); } return 0; }
题意:有n个人围成环玩游戏,每个人的位置按顺时针从1~n排列,一共m轮,每轮选出一个领导者,用l[i]表示第i轮的领导是谁,每个人当领导的时候,他会选择他后面第a[i]个人担任下一轮的领导,并且a[i] 只能是 1 ~ n 中的值,并且每个人的a[i] 都不一样,换句话说,n个人的a[i]组成 1 ~ n ,给出了n,m, l[i],求a[i],如果不存在,输出-1
思路:我们注意到,每一轮的领导者都是上一轮领导后的第a[i]位,那么 a[i-1] = l[i] - l[i-1] ,又因为n个人排成环,所以当 l[i] < l[i-1] 的时候,a[i-1] = l[i] + n - l[i-1],这样就可以求出a[i]了,对于不确定的a[i],我们给其一个没有出现过的数当成这个数的a[i]即可。而如果某两个人的a[i]相同,那么就不存在,输出-1
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x, y) cout<<"["<<x<<","<<y<<"] " #define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; const int Max = 1e5 + 10; int n, m; int leader[Max]; //记录第i个领导者的位置 int a[Max]; //每次移动距离 int vis[Max]; int main() { #ifdef LOCAL //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); #endif while (scanf("%d%d", &n, &m) != EOF) { memset(a, -1, sizeof(a)); memset(vis, 0, sizeof(vis)); bool ok = true; scanf("%d", leader + 1); for (int i = 2; i <= m; i++) { scanf("%d", leader + i); int temp = 0; int add = 0; if(leader[i] <= leader[i-1]) { add += n; } temp = leader[i] + add - leader[i-1]; if (a[leader[i - 1]] == -1 || a[leader[i - 1]] == temp) //同一个人同一个a[i]没有问题 { if (vis[temp] && a[leader[i - 1]] == -1) //不同的人有相同的a[i] { ok = false; } else { a[leader[i - 1]] = temp; vis[temp] = true; } } else { ok = false; } } if (!ok) { printf("-1\n"); } else { for (int i = 1; i <= n; i++) { if (a[i] != -1) { printf("%d ", a[i]); } else { for (int j = 1; j <= n; j++) { if (!vis[j]) { printf("%d ", j); vis[j] = true; break; } } } } printf("\n"); } } return 0; }
题意:在一个 n * m 的房间内,有 d 个沙发,每个沙发占两个单位面积,我们将(x,y)视作一单位面积,给出每个沙发的位置x1,y1,x2,y2 ,代表这个沙发的位置为 (x1,y1),(x2,y2),保证没有两个及以上的沙发占用同一个位置,最后给出我们需要的沙发的信息cntL,cntR,cntB,cnrT,分别代表我们需要找的沙发的 左边沙发的个数,右边沙发的个数,底部沙发的个数,顶部沙发的个数,注意,只要两个沙发A,B,满足 A.x < B.x ,x = x1,x2,那么A就在B的左边,如果 A.y < B.y ,y = y1,y2,那么A在B的顶部,也就是说,y值大的在底部,问满足这个要求的沙发的编号,如果不存在,输出-1
思路:思路很简单,不过很多细节需要注意,具体方法如下
当前沙发左边的沙发数:所有左边界小于当前沙发右边界的沙发总数,
1、如果找到第一个大于等于当前沙发右边界的,
1) 如果当前沙发左右边界相等,那么此前的都是
2)如果不相等,减去自身;
2、如果没有大于等于当前沙发右边界的,那么此前所有的沙发都是的
当前沙发右边的沙发数:所有右边界大于当前沙发左边界的沙发总数,
1、如果找到第一个大于当前沙发左边界的,
1)如果当前沙发左右边界相等,那么此后的都是
2)如果不相等,减去自身
2、如果没有找到大于当前沙发左边界的,那么就没有
当前沙发底部的沙发数:所有上边界大于当前沙发下边界的沙发总数
1、找到第一个大于当前沙发下边界的沙发,
1) 如果上下边界相同,那么此后的都是
2)如果不相等,减去自身
2、如果没有大于当前沙发下边界的沙发,那么就没有
当前沙发顶部的沙发数:所有下边界小于当前沙发上边界的沙发总数
1、如果找到第一个大于等于当前沙发上边界的沙发
1) 如果上下边界相同,那么此前的都是
2)如果不相等,那么减去自身
2、如果没有大于等于当前沙发上边界的沙发,那么全都是
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #include<fstream> #include<vector> #include<stack> #include <map> #include <iomanip> #define bug cout << "**********" << endl #define show(x, y) cout<<"["<<x<<","<<y<<"] " #define LOCAL = 1; using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const ll mod = 1e9 + 7; const int Max = 1e5 + 10; struct Node { int x1, y1, x2, y2; } node[Max]; int d, n, m; int cntL, cntR, cntT, cntB; int R[Max], L[Max], T[Max], B[Max]; //记录四个边界 int main() { #ifdef LOCAL //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout); #endif while (scanf("%d%d%d", &d, &n, &m) != EOF) { for (int i = 1; i <= d; i++) { scanf("%d%d%d%d", &node[i].x1, &node[i].y1, &node[i].x2, &node[i].y2); if (node[i].x1 > node[i].x2) swap(node[i].x1, node[i].x2); if (node[i].y1 > node[i].y2) //大数为底部 swap(node[i].y1, node[i].y2); L[i] = node[i].x1; //记录每个沙发的左边界 R[i] = node[i].x2; //记录每个沙发的右边界 B[i] = node[i].y1; //记录每个沙发的下边界 T[i] = node[i].y2; //记录每个沙发的上边界,值大的为上边界 //cout << "L: " << L[i] << " R: " << R[i] << " B: " << B[i] << " T: " << T[i] << endl; } scanf("%d%d%d%d", &cntL, &cntR, &cntT, &cntB); sort(R + 1, R + 1 + d); sort(L + 1, L + 1 + d); sort(B + 1, B + 1 + d); sort(T + 1, T + 1 + d); //均升序排序 int id = -1; for (int i = 1; i <= d; i++) //枚举沙发 { int ansL = lower_bound(L + 1, L + 1 + d, node[i].x2) - L; if (ansL == d + 1) //没有找到大于等于当前沙发右边界的沙发 { ansL = d - 1; } else { ansL--; if (node[i].x1 != node[i].x2) //排除自身左边界的影响 { ansL--; } } //cout <<"ansL: "<<ansL<<endl; if (ansL != cntL) continue; /**********************************************/ int ansR = upper_bound(R + 1, R + 1 + d, node[i].x1) - R; if (ansR == d + 1) //没有找到大于当前沙发左边界的沙发,那么都是 { ansR = 0; } else { ansR = d - ansR + 1; if (node[i].x1 != node[i].x2) //排除自身右边界的影响 { ansR--; } } //cout <<"ansR: "<<ansR<<endl; if (ansR != cntR) continue; /**********************************************/ int ansB = upper_bound(T + 1, T + 1 + d, node[i].y1) - T; if (ansB == d + 1) //没有找到大于当前沙发下边界的沙发,那么没有 { ansB = 0; } else { ansB = d - ansB + 1; if (node[i].y1 != node[i].y2) { ansB--; } } //cout <<"ansB: "<<ansB<<endl; if (ansB != cntB) continue; /**********************************************/ int ansT = lower_bound(B + 1, B + 1 + d, node[i].y2) - B; if (ansT == d + 1) { ansT = d - 1; } else { ansT--; if (node[i].y1 != node[i].y2) { ansT--; } } //cout <<"ansT: "<<ansT<<endl; if (ansT != cntT) continue; /**********************************************/ id = i; break; } printf("%d\n", id); } return 0; } //当前沙发左边的沙发数:所有左边界小于当前沙发右边界的沙发总数, //1、如果找到第一个大于等于当前沙发右边界的, //1) 如果当前沙发左右边界相等,那么此前的都是,2)如果不相等,减去自身; //2、如果没有大于等于当前沙发右边界的,那么此前所有的沙发都是的 //当前沙发右边的沙发数:所有右边界大于当前沙发左边界的沙发总数, //1、如果找到第一个大于当前沙发左边界的, //1)如果当前沙发左右边界相等,那么此后的都是,2)如果不相等,减去自身 //2、如果没有找到大于当前沙发左边界的,那么就没有 //当前沙发底部的沙发数:所有上边界大于当前沙发下边界的沙发总数 //1、找到第一个大于当前沙发下边界的沙发, //1) 如果上下边界相同,那么此后的都是,2)如果不相等,减去自身 //2、如果没有大于当前沙发下边界的沙发,那么就没有 //当前沙发顶部的沙发数:所有下边界小于当前沙发上边界的沙发总数 //1、如果找到第一个大于等于当前沙发上边界的沙发 //1) 如果上下边界相同,那么此前的都是,2)如果不相等,那么减去自身 //2、如果没有大于等于当前沙发上边界的沙发,那么全都是