A. Table
简单题。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <math.h>
using namespace std;
int main()
{
int n, m, ans;
scanf("%d%d", &n, &m);
int x;
ans = n*m;
for (int i=1; i<=n; ++i) for(int j=1; j<=m; ++j)
{
scanf("%d", &x);
if (x)
{
if (1==i || 1==j || i==n || j==m) ans = 2;
else ans = min(ans, 4);
}
}
printf("%d\n", ans);
}
B. Permutation
算发现规律吧。
对于.后面的一个式,保持结果为n;前面的式子大小范围为[n,(n+1)+(n+2)...+(n+n) - (1+2+3...+n)], 所以,只要调整前面式子,让结果为2k+n(因为0<=k<=n/2)。
如:
1 2 3 4 结果为 2 - 2 = 0,调换1 3位置,结果为4 - 2 = 2;
每被4整除的连续4个数中,调换1 3位置,值就增加2。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
using namespace std;
#define clr(p,v) memset(p,v,sizeof(p))
const int maxn = 110 ;
const int maxm = 1000010 ;
int n, m, ans, res, k;
int d[maxn];
bool vis[maxn], used[maxn];
void init()
{
ans = res = 0;
clr(vis, 0);
clr(used, 0);
clr(d, 0);
}
int main()
{
scanf("%d%d", &n, &k);
int cnt = 0;
for (int i=1; i<=k; ++i)
{
cnt += 4;
int x = (i-1)*4+1;
printf("%d %d %d %d ", x+2, x+1, x, x+3);
}
for(int i=cnt+1; i<=n+n; ++i)
printf("%d ", i);
puts("");
return 0;
}
C. Prime Number
通分后,
分母 = x^(a1+a2+...an)
分子 = x^(a2+a3+...an) + x^(a1+a3+...an) + ... + x^(a2+a3+...a(n-1))
找公约数,从分子下手,提取公因式,观察可了解到,都是x^n次方,所以,找最小的n即可(注意有多个最小,要把最小的相加,可能比第2小大,所以,要再判断,循环这个过程)
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define clr(p,v) memset(p,v,sizeof(p))
const int maxn = 100010 ;
const int mod = 1000000007 ;
typedef __int64 LL;
int n;
LL x, sum, ans;
LL d[maxn];
map<LL, LL> mp;
map<LL, LL>::iterator iter;
void Init()
{
mp.clear();
sum = 0;
}
void Input()
{
scanf("%d%I64d", &n, &x);
for (int i=1; i<=n; ++i)
{
scanf("%I64d", &d[i]);
sum += d[i];
}
}
LL QuickPow(LL x, LL num)
{
if (num == 0)
return 1;
if (num == 1)
return x;
if (num % 2 == 1)
{
return x*QuickPow(x, num-1)%mod;
}
else
{
LL tmp = QuickPow(x, num>>1)%mod;
return tmp*tmp%mod;
}
/*
LL ans = 1;
while (num)
{
if (1 == num % 2)
ans = ans*x%mod;
x = x*x%mod;
num >>= 1;
}
return ans % mod;
*/
}
void Solve()
{
ans = sum;
for (int i=1; i<=n; ++i) ++mp[sum - d[i]];
for (iter = mp.begin(); iter != mp.end(); ++iter)
{
if (iter->second >= x)
{
mp[iter->first + 1] += (iter->second)/x;
(iter->second) %= x;
}
if (iter->second)
{
ans = min(ans, iter->first);
break;
}
}
ans = QuickPow(x, ans);
}
void Output()
{
printf("%I64d\n", ans);
}
int main()
{
Init();
Input();
Solve();
Output();
return 0;
}
D. Pair of Numbers
换种思维方式,不要从下面入手,找连续区间内,存在一个能被其他所有数整除。
假设这个数是ai,从i向两端扩展,找到不能被ai整除的最左l,最右r位置,并记录这两个端点。
if (y % x == 0 && z % y == 0) => z % x == 0 利用这个性质,x能被y整除时,下个数就直接跳到端点之后一个数处理;如果不能整除,也就到达端点。
(该方法可解答http://acm.fzu.edu.cn/problem.php?pid=2136)
/*
题意:
给出长度为N的整形数组,找出所有 Max(r-l) 中存在一个数能被其他所有数整除
思路:
假设以i为那个数,向两边扩展l[i], r[i]
if (r[i-1] % r[i] == 0 ) l[i] = i-l[i-1] + L;
else l[i] += 0;
同理,r[i]
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
#define clr(p,v) memset(p, v, sizeof(p))
const int maxn = 300010 ;
const int mod = 1000000007 ;
int n, cnt, mx;
int d[maxn], ans[maxn];
int l[maxn], r[maxn];
bool vis[maxn];
void Init()
{
cnt = 0;
mx = 1;
d[0] = mod;
clr(vis, false);
}
void Input()
{
scanf("%d", &n);
for (int i=1; i<=n; ++i)
scanf("%d", &d[i]);
}
void Solve()
{
// temp int
int iMid;
// left
l[1] = 0;
for (int i=2; i<=n; ++i)
{
iMid = i-1;
if (d[iMid] % d[i] == 0)
{
while(1)
{
iMid = l[iMid];
if (!iMid || d[iMid] % d[i] != 0)
break;
}
}
l[i] = iMid;
}
// right
r[n] = n;
for (int i=n-1; i; --i)
{
iMid= i+1;
if (d[iMid] % d[i] == 0)
{
while (1)
{
iMid = r[iMid] + 1;
if (iMid > n || d[iMid] % d[i] != 0)
break;
}
}
r[i] = --iMid;
}
// get ans
for (int i=1; i<=n; ++i)
{
if (mx < r[i] - l[i])
{
mx = r[i] - l[i];
cnt = 0;
ans[cnt++] = l[i]+1;
}
else if (mx == r[i] - l[i])
{
ans[cnt++] = l[i]+1;
}
}
// remove reused
iMid = 0;
for (int i=0; i<cnt; ++i)
{
if (!vis[ans[i]])
{
vis[ans[i]] = true;
ans[iMid++] = ans[i];
}
}
cnt = iMid;
}
void Output()
{
printf("%d %d\n", cnt, mx-1);
for (int i=0; i<cnt; ++i) printf("%d ", ans[i]);
puts("");
}
int main()
{
Input();
Init();
Solve();
Output();
return 0;
}
E. Neatness
/*
题意:
要关掉所有房间的灯,一个步骤要么开灯,要么关灯,要么向有灯的方向前进一格。输出一种关掉所有灯的方案。不能关掉所有灯输出NO
解题思路:
dfs,搜索时,点灯,回退时,关灯
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
using namespace std;
#define clr(p,v) memset(p,v,sizeof(p))
const int maxn = 505 ;
const int maxm = 1000010 ;
int n, sx, sy, sum, cnt;
int mk[maxn][maxn];
char str[maxm];
int dx[] = {0, 0, 1, -1};
int dy[] = {-1, 1, 0, 0};
char forward[] = {'L', 'R', 'D', 'U'};
char back[] = {'R', 'L', 'U', 'D'};
bool vis[maxn][maxn];
void Init()
{
cnt = 0;
sum = 0;
clr(vis, false);
}
void Input()
{
scanf("%d%d%d", &n, &sx, &sy);
for (int i=1; i<=n; ++i) for (int j=1; j<=n; ++j)
{
scanf("%d", &mk[i][j]);
sum += mk[i][j];
}
}
bool IsOut(int x, int y)
{
if (x<1 || y<1 || x>n || y>n)
return true;
return false;
}
bool Can(int x, int y, int i)
{
while (1)
{
if (IsOut(x, y) || vis[x][y])
return false;
if (1 == mk[x][y])
return true;
x += dx[i];
y += dy[i];
}
}
void dfs(int x, int y)
{
if (0 == mk[x][y])
{
mk[x][y] = 1;
str[cnt++] = '1';
++sum;
}
vis[x][y] = true;
for (int i=0; i<4; ++i)
{
int tx = x + dx[i];
int ty = y + dy[i];
if (IsOut(tx, ty) || vis[tx][ty] || !Can(tx, ty, i))
continue;
str[cnt++] = forward[i];
dfs(tx, ty);
str[cnt++] = back[i];
}
str[cnt++] = '2';
--sum;
}
void Output()
{
if (0 == sum)
{
str[cnt++] = '\0';
puts("YES");
puts(str);
}
else
{
puts("NO");
}
}
int main()
{
Init();
Input();
dfs(sx, sy);
Output();
return 0;
}