题意:
有N个社团,每个社团三个属性A,B,C,表示会向编号A+k*C的同学发传单(k=0,1,2... && A+k*C <= B)。题目保证最多有一个人收到的传单数是奇数。求如果有人收到传单是奇数,输出编号和他收到的传单数。
思路:
观察最后情况,可以发现,要么每个人都是偶数。要么有一个是奇数。观察其前缀和,发现奇数那个人之前的前缀和都是偶数,之后都是奇数。所以,二分之。
代码:
(上交大牛代码……)
#include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #include <cmath> #include <iostream> #include <algorithm> using namespace std; int n, a[100001][3]; long long sum; bool check(int now){ long long sum = 0; for (int i = 1; i <= n; i++) if (now >= a[i][0]) { int Right = min(a[i][1], now); if (a[i][2]) sum += (long long)(Right - a[i][0]) / a[i][2] + 1; else sum++; } return(sum & 1); } int read(){ char ch; for (ch = getchar(); ch < '0' || ch > '9'; ch = getchar()); int cnt = 0; for (; ch >= '0' && ch <= '9'; ch = getchar()) cnt = cnt * 10 + ch - '0'; return(cnt); } int main(){ //freopen("j.in", "r", stdin); //freopen("j.out", "w", stdout); for (;;) { if (scanf("%d", &n) != 1) return 0; sum = 0; int Max = 0; for (int i = 1; i <= n; i++) { a[i][0] = read(); a[i][1] = read(); a[i][2] = read(); if (a[i][2]) sum += (long long)(a[i][1] - a[i][0]) / a[i][2] + 1; else sum++; Max = max(Max, a[i][1]); } if (!(sum & 1)) { printf("DC Qiang is unhappy. "); continue; } long long Left = 0, Right = Max, Mid = (Left + Right) >> 1; while (Left + 1 < Right) { if (check(Mid)) Right = Mid; else Left = Mid; Mid = (Left + Right) >> 1; } printf("%d", Right); int cnt = 0; for (int i = 1; i <= n; i++) if (Right >= a[i][0] && Right <= a[i][1] && !((Right - a[i][0]) % a[i][2])) ++cnt; printf(" %d ", cnt); } }