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" <
DIV 2 B
给一个序列,给Q个查询。第一个人每次从左往右找,第二个人每次从右往左找,问分别需要查询几次。
更水,直接Map一下就好了。
map 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 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>=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 <
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();
}