DIV 2 A
给三个点,为从A - B - C的过程中,是要向左转还是右转还是直行。
方法很简单,叉积嘛。
#define typec long long struct Point2D{ typec x,y; Point2D(){} Point2D(typec _x,typec _y):x(_x),y(_y){}; void input(){ cin >> x >> y; } void output(){ printf("%.2f %.2f\n",x,y); } typec len(){ return hypot(x,y); } typec len2(){ return x*x+y*y; } typec distance(Point2D p){ return hypot(x-p.x,y-p.y); } Point2D add(Point2D p){ return Point2D(x+p.x,y+p.y); } Point2D sub(Point2D p){ return Point2D(x-p.x,y-p.y); } Point2D mul(typec b){ return Point2D(x*b,y*b); } Point2D div(typec b){ return Point2D(x/b,y/b); } typec dot(Point2D p){ return x*p.x+y*p.y; } typec det(Point2D p){ return x*p.y-y*p.x; } typec rad(Point2D a,Point2D b){ Point2D p=*this; return fabs(atan2(fabs(a.sub(p).det(b.sub(p))),a.sub(p).dot(b.sub(p)))); } } A, B, C ,D , E; int main(){ A.input(); B.input(); C.input(); D = B.sub(A); E = C.sub(A); LL res = D.det(E); if (res == 0) cout << "TOWARDS" <<endl; else if (res < 0) cout << "RIGHT" << endl; else cout << "LEFT" << endl; }
DIV 2 B
给一个序列,给Q个查询。第一个人每次从左往右找,第二个人每次从右往左找,问分别需要查询几次。
更水,直接Map一下就好了。
map<LL , LL> Mengl , Mengr; const int N = 200000; LL a[N]; int n; void solve(){ Mengl.clear(); Mengr.clear(); for (int i = 1 ; i <= n ; ++i){ cin >> a[i]; if (Mengl.find(a[i]) == Mengl.end()) Mengl[a[i]] = i; } for (int i = n ; i >= 1 ; --i){ if (Mengr.find(a[i]) == Mengr.end()) Mengr[a[i]] = n - i + 1; } int m ; cin >> m; LL ansa = 0 , ansb = 0; while (m--){ LL x; cin >>x; ansa += Mengl[x]; ansb += Mengr[x]; } cout << ansa << " " << ansb << endl; } int main(){ while (cin >> n) solve(); }
A
题意是: a , b ,c 三个站, 有1~n三个人站在a上面,如果有一个人要从 x -> y 的话那么这个人的编号必须是 x , y 中所有人中编号最大的。求移动次数。
对于n个数来说需要经历以下几步:
n _ _ 0
1 _ n-1 f(n-1)
_ 1 n-1 1
n-1 1 _ f(n-1)
n-1 _ 1 1
_ _ n f(n-1)
所以 f(n) = 3 * f(n-1) + 2
于是 f(n) + 1 = 3 * ( f(n - 1) + 1)
于是就能推出来 f(n) = 3 ^ n - 1
注意 -1 和Mod m 的关系
#define typec long long typec powerMod(typec x, typec k, typec m) { typec res = 1; while(x %= m, k) { if(k&1) res *= x, res %= m; x *= x, k >>=1; } return res; } #define LL long long LL n , m; int main(){ while (cin >> n >> m){ LL res = powerMod(3LL , n , m); res = (res - 1LL + m) % m; cout << res << endl; } }
B
给n个堆,每次合并的代价是较小值。
Q个询问,每次给一个k , 每一堆最多被加k次,问最少要用多少代价合并为一堆。
Orz孟神V587
贪心, 先sort 一下
f[i][j] 代表 前i堆合并为j堆的最小代价。 最终求的就是f[n][1]
f[i][j] = f[i - j][j * k] + sum[i - j] .即按照 k ^ p 递归, 每次是用前 k ^ p 堆分别放到 k ^ (p - 1) 堆
特判 k = 1 的情况,否则可能超时
const int N = 200000; LL a[N] , sum[N] , pre[N]; LL n , Q , k; vector<LL> ans; LL getans(LL idx , LL number){ LL ret = 0; while (idx >= number){ ret += sum[idx - number]; idx -= number; number *= k; } return ret; } void solve(){ a[0] = sum[0] = 0; for (int i = 1 ; i <= n ; ++i) cin >> a[i]; sort(a + 1 , a + n + 1); for (int i = 1 ; i <= n ; ++i){ sum[i] = sum[i - 1] + a[i]; pre[i] = pre[i - 1] + sum[i]; } ans.clear(); cin >> Q; while (Q--){ cin >> k; if (k == 1) ans.PB(pre[n - 1]); else{ ans.PB( getans(n , 1) ); } } for (int i = 0 ; i < ans.size(); ++i){ if (i) printf(" "); cout << ans[i]; } cout << endl; } int main(){ while (cin >> n) solve(); }
C
首先Fibonacci数列有性质 : GCD( f[i] , f[j] ) = f [ GCD(i , j) ]
所以也就是求 [l , r ] 中 k 个数 的最大公约数是几。 注意,这里没有单调性,所以不能二分!!!!
因为 函数 r / x - (l - 1) / x 分段单调( 在 r / x = r / y ) 上单调。
所以只需要 段内 x 最大即可。
于是枚举 i = 1 ~ \sqrt{r} 中 i 和 r / i 即可
#define LL long long const int maxn=2; #define typec LL LL modo; class Mat { public: int Matn,Matm; typec a[maxn][maxn]; Mat() { Matn=0; Matm=0; memset(a,0,sizeof(a)); } void output(); void init(); void initI(); Mat mul(const Mat &a); Mat power(const Mat&a,LL k); }; void Mat::output() { for (int i=0;i<Matn;++i) { for (int j=0;j<Matm;++j) { if (j!=0) printf(" "); printf("%d",a[i][j]); } printf("\n"); } } void Mat::init() { Matn=0; Matm=0; memset(a,0,sizeof(a)); } Mat Mat::mul(const Mat &A) { Mat c; c.Matn=Matn; c.Matm=A.Matm; for (int i=0;i<Matn;++i) for (int j=0;j<A.Matm;++j) { for (int k=0;k<Matm;++k) { c.a[i][j]=(c.a[i][j]+(a[i][k]*A.a[k][j])%modo)%modo; } } return c; } void Mat::initI() { memset(a,0,sizeof(a)); for (int i=0;i<Matn;++i) a[i][i]=1LL; } Mat Mat::power(const Mat& a,LL k) { Mat c=a,b; b.init(); b.Matn=a.Matn;b.Matm=a.Matm; b.initI(); while (k) { if (k & 1LL) b=b.mul(c); c=c.mul(c); k>>=1LL; } return b; } LL gao(LL t){ if (t <= 1) return 1LL; Mat a; a.Matm = a.Matn = 2; a.a[0][0] = 1LL , a.a[1][0] = 1LL , a.a[0][1] = 1LL; a = a.power(a , t - 1LL); return a.a[0][0]; } LL l , r , k; /* 1000000000 1 1000000000000 5 */ LL check(LL x){ return r / x - (l - 1LL) / x; } void solve(){ LL ans = 1; for (LL i = 1 ; i * i <= r ; ++i){ if (check(i) >= k && i > ans) ans = i; LL j = r / i; if (check(j) >= k && j > ans) ans = j; } cout << gao(ans) % modo <<endl; }
D
给一个100 * 100 的数阵 , 每次可以转换一行或者一列的正负。求一个解,使得每行每列的和都>=0
每次找到最小的一行或者一列, 反一下就行了。。
const int N = 200; int a[N][N]; int suml[N] , sumc[N]; bool reversel[N] ,reversec[N]; int n , m; void rev(int x , int y){ suml[x] -= 2 * a[x][y]; sumc[y] -= 2 * a[x][y]; a[x][y] = -a[x][y]; } void revl(int line){ reversel[line] ^= 1; for (int i = 0 ; i < m ; ++i) rev(line , i); } void revc(int column){ reversec[column] ^= 1; for (int i = 0 ; i < n ; ++i) rev(i , column); } void solve(){ memset(suml , 0 , sizeof(suml)); memset(sumc , 0 , sizeof(sumc)); memset(reversel , 0 , sizeof(reversel)); memset(reversec , 0 , sizeof(reversec)); for (int i = 0 ; i < n ; ++i) for (int j = 0 ; j < m ; ++j){ cin >> a[i][j]; suml[i] += a[i][j]; sumc[j] += a[i][j]; } int ml , mc , sl , sc; do{ ml = min_element(suml , suml + n) - suml; mc = min_element(sumc , sumc + m) - sumc; //printf("%d %d\n",suml[ml] , sumc[mc]); sl = suml[ml] , sc = sumc[mc]; if (suml[ml] <= sumc[mc] && suml[ml] < 0) revl(ml); else if (sumc[mc] < suml[ml] && sumc[mc] < 0) revc(mc); }while (sl < 0 || sc < 0); int ansl = 0 , ansc = 0; for (int i = 0 ; i < n ; ++i) if (reversel[i]) ++ansl; for (int i = 0 ; i < m ; ++i) if (reversec[i]) ++ansc; printf("%d",ansl); for (int i = 0 ; i < n ; ++i) if (reversel[i]) printf(" %d",i + 1); printf("\n"); printf("%d",ansc); for (int i = 0 ; i < m ; ++i) if (reversec[i]) printf(" %d", i + 1); printf("\n"); } int main(){ while (cin >> n >> m) solve(); }