这个比赛好像不是很有名气,参加的人不多,前五题感觉比较平,题目有简单的也有中等的,但应该说不难,反正我是AK了。第3,4题还是很好的。
链接:http://www.codechef.com/BTCD2013/
1:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#include<stack>
#include<deque>
#include<list>
#include<set>
#include<vector>
#include<iomanip>
#include<cctype>
#include<string>
#include<memory>
#include<map>
#include<sstream>
#define mem(a) memset(a, 0, sizeof(a))
#define For(i, n) for(int i = 0; i < (n); ++i)
#define sl(a) strlen(a)
typedef long long LL;
typedef double dou;
const int Mod = 1000000007;
const double eps = 1e-8;
const LL inf = 1e18;
const int inf1 = 1e9;
const int N = 100005;
using namespace std;
int a[N], l[N], r[N], dp[N][20];
int main()
{
LL n, m, t, i, j, k;
cin >> t;
while (t--)
{
cin >> n >> m;
cout << n * m - n - m << endl;
}
return 0;
}
是一个数论结论,(a, b) = 1, a, b > 0 时ax + by (x, y >= 0) 不能表示的最大的整数是a * b - a - b.
证明: a 或 b 是1的情况是显然的,下设a > 1, b > 1.
首先a * b - a - b不能被表示。反证,设a * b - a - b = a * m + b * n 则 a * b = (m + 1)*a + (n + 1) * b.右边系数全部大于1。注意到左边是a的倍数,所以a |(n + 1)*b, 因为(a, b) = 1, 所以a | (n + 1), 所以(n + 1) * b > a * b, 矛盾。再证a * b - a - b + i (i > 0) 能被表示。因为a,b互质,最大公约数就是1,根据辗转相减的方法知m*a+n*b=1,不妨假设m>0,n<0,于是a*b-a-b+i=a*b-a-b+i*(m*a+n*b)。因为m>1(m=0意味着n*b=1不可能的),所以a*b-a-b+i*(m*a+*b)=(i*m-1)a+(a+i*n-1)*b,i*m-1>0,现在只要证明a+i*n-1>=0,因为i*m*a+i*n*b=i,如果,|i*n|>j*a其中j>0,那么i*m*a=i+|i*n|*b>j*a*b,所以i*m>j*b,所以i*m*a+i*n*b=(i*m-j*b)a-(|i*n|-j*a)*b=i,说明|i*n|>j*a时,我们就能调整i*m,i*n使得|i*n|<a,因此|i*n|<=a-1, 所以a+i*n-1>=0于是得证。
2:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#include<stack>
#include<deque>
#include<list>
#include<set>
#include<vector>
#include<iomanip>
#include<cctype>
#include<string>
#include<memory>
#include<map>
#include<sstream>
#define mem(a) memset(a, 0, sizeof(a))
#define For(i, n) for(int i = 0; i < (n); ++i)
#define sl(a) strlen(a)
typedef long long LL;
typedef double dou;
const int Mod = 1000000007;
const double eps = 1e-8;
const LL inf = 1e18;
const int inf1 = 1e9;
const int N = 100005;
using namespace std;
struct po
{
list<int>s;
}p[20005];
int f[20005], vis[20005];
void dfs(int e, int s)
{
vis[e] = 1;
f[e] = s;
list<int> :: iterator it = p[e].s.begin();
while (it != p[e].s.end())
{
if (vis[*it] == 0)
dfs(*it, e);
it++;
}
}
int main()
{
LL n, m, t, i, j, k, x, y;
cin >> t;
while (t--)
{
cin >> n >> x >> y;
for (i = 1; i <= n; ++i)
{
if (i != x)
{
cin >> m;
p[i].s.push_back(m);
p[m].s.push_back(i);
}
}
dfs(y, y);
for (i = 1; i <= n; ++i)
{
if (i != y)
cout << f[i] << ' ';
}
cout << endl;
for (i = 1; i <= n; ++i) p[i].s.clear();
mem(vis);
}
return 0;
}
比较水的DFS.不多说。
5:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#include<stack>
#include<deque>
#include<list>
#include<set>
#include<vector>
#include<iomanip>
#include<cctype>
#include<string>
#include<memory>
#include<map>
#include<sstream>
#define mem(a) memset(a, 0, sizeof(a))
#define For(i, n) for(int i = 0; i < (n); ++i)
#define sl(a) strlen(a)
typedef long long LL;
typedef double dou;
const int Mod = 1000000007;
const double eps = 1e-8;
const LL inf = 1e18;
const int inf1 = 1e9;
const int N = 100005;
using namespace std;
int num[200], vis[40], f[200], vv[200];
int main()
{
LL n, m, t, i, j, k, len, cnt, re;
char s[100];
cin >> t;
while (t--)
{
mem(num), mem(s), mem(vis), mem(f), mem(vv);
cin >> s;
len = sl(s);
cnt = re = 0;
for (i = 0; i < len; ++i) num[s[i]]++;
for (i = 0; i < 200; ++i) if (num[i]) cnt++;
if (cnt == 1)
{
cout << (1 << len) - 1 << endl;
}
else
{
f[s[0]] = 1, vis[1] = re = 1, vv[s[0]] = 1;
for (i = 1; i < len; ++i)
{
if (vv[s[i]]) re = re * cnt + f[s[i]];
else
{
for (j = 0; j < 40 && vis[j]; ++j);
vis[j] = 1, f[s[i]] = j, vv[s[i]] = 1;
re = re * cnt + j;
}
}
cout << re << endl;
}
}
return 0;
}
(题意就是任给一串字符,你可以认为它是任何进制的数,但求它在十进制下的最小可能值)注意下进制数不能是1就可以了(wa了两次),首位也不能为0。
3和4是两道我觉得比较好的题。
思路都是DP, 其实3只能算递推,并没有涉及到动态保存能带来的好处,其实就是先算好了答案,放在数组里而已。代码中后有着重的地方是关键。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#include<stack>
#include<deque>
#include<set>
#include<vector>
#include<iomanip>
#include<cctype>
#include<string>
#include<memory>
#include<map>
#include<sstream>
#pragma warning (disable : 4996)
#define mem(a) memset(a, 0, sizeof(a))
#define For(i, n) for(int i = 0; i < (n); ++i)
#define sl(a) strlen(a)
typedef long long LL;
typedef double dou;
const int Mod = 1000000007;
const double eps = 1e-8;
const LL inf = 1e18;
const int inf1 = 1e9;
const int N = 100005;
using namespace std;
#define M 12
LL dp[10][10][600];
LL ans[10][600];
int main ()
{
LL i, j, k, n, m, t, re;
for (i = 1; i < 10; ++i) //最大可取数字为i,首位为j,长度为k
dp[i][i][i + 1] = dp[i][0][i + 1] = 1;
for (i = 1; i < 10; ++i)
for (k = i + 2; k < 510; ++k) //*****//
for (j = 0; j <= i; ++j)
{
if (j == 0) dp[i][0][k] = (dp[i][1][k - 1] + dp[i - 1][0][k - 1]) % Mod; //******************//
else if (j == i) dp[i][i][k] = (dp[i][i - 1][k - 1] + dp[i - 1][i - 1][k - 1]) % Mod;
else dp[i][j][k] = (dp[i][j - 1][k - 1] + dp[i][j + 1][k - 1]) % Mod; //******************//
}
for (i = 1; i < 10; ++i)
for (k = i + 1; k < 510; ++k) //****//
for (j = 1, ans[i][k] = ans[i][k - 1]; j <= i; ++j) //*****//
ans[i][k] = (ans[i][k] + dp[i][j][k]) % Mod;
cin >> t;
while (t--)
{
scanf("%lld%lld", &n, &m);
if (n > m) printf("0\n");
else printf("%lld\n", ans[n - 1][m]);
}
return 0;
}
4:
首先考虑一个两段开的区间(i , j), dp[i][j]表示从a[i]到a[j]的所有可能方案的代价最小值。设两个哨兵0, n+1.枚举i, j 之间所有第一步可取的方案,划归为子问题。取最小即可。最后写出来的代码倒是很简洁。(一开始贪心,猜的策略。。。wa了好多次)。复杂度是Z*Z*Z,10^6可以接受。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#include<stack>
#include<deque>
#include<list>
#include<set>
#include<vector>
#include<iomanip>
#include<cctype>
#include<string>
#include<memory>
#include<map>
#include<sstream>
#define mem(a) memset(a, 0, sizeof(a))
#define For(i, n) for(int i = 0; i < (n); ++i)
#define sl(a) strlen(a)
typedef long long LL;
typedef double dou;
const int Mod = 1000000007;
const double eps = 1e-8;
const LL inf = 1e18;
const int inf1 = 1e9;
const int N = 100005;
using namespace std;
int a[105], dp[105][105];
int main()
{
int n, m, re, t, i, j, k;
cin >> t;
while (t--)
{
cin >> m >> n;
mem(dp);
for (i = 1; i <= n; ++i) cin >> a[i];
a[n + 1] = m + 1;
for (i = 2; i <= n + 1; ++i)
for (j = 0; j + i <= n + 1; ++j)
{
for (k = j + 1; k < i + j; ++k)
{
if (k == j + 1) dp[j][i + j] = (a[i + j] - a[j] - 2 + dp[j][k] + dp[k][i + j]);
else dp[j][i + j] = dp[j][i + j] > (a[i + j] - a[j] - 2 + dp[j][k] + dp[k][i + j]) ? (a[i + j] - a[j] - 2 + dp[j][k] + dp[k][i + j]) : dp[j][i + j];
}
}
cout << dp[0][n + 1] << endl;
}
return 0;
}
希望22号,另五道不要忽然变得特别难,能拿个好的名次.^_^
接着写。。。。无力吐槽数据。。。
6:
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<iostream>
#define LL long long
using namespace std;
set<int> p;
bool witness(LL a,LL n)
{
LL t,d,x;
d=1;
int i=ceil(log(n-1.0)/log(2.0)) - 1;
for(;i>=0;i--)
{
x=d; d=(d*d)%n;
if(d==1 && x!=1 && x!=n-1) return true;
if( ((n-1) & (1<<i)) > 0)
d=(d*a)%n;
}
return d==1 ? false : true;
}
bool miller_rabin(LL n)
{
int s[]={2,7,61};
if(n==2) return true;
if(n==1 || ((n&1)==0)) return false;
for(int i=0;i<3;i++)
if(witness(s[i], n)) return false;
return true;
}
int main()
{
int n,cnt, x, y, i, j, t, en;
cin >> t;
while(t--)
{
cin >> x >> y;
cnt=0;
for (i = 1; i * i < y / 2; ++i)
{
en = (int) sqrt(y - i * i + 0.5);
for (j = i + 1; j <= en; j += 2)
if (i * i + j * j >= x)
if (miller_rabin(i * i + j * j))
{
if (!p.count(i * i + j * j))
{
cnt++;
p.insert(i * i + j * j);
}
}
}
if (x <= 2 && y >= 2) cnt++;
cout << cnt << endl;
p.clear();
}
return 0;
}
7:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(a) memset(a, 0, sizeof(a))
#define N 100005
#define M 1000005
#define LL long long
#pragma warning (disable : 4996)
using namespace std;
struct po
{
int x, l, cnt, id;
bool operator < (const po &t) const
{
return x < t.x;
}
}p[N];
bool cmp(po a, po b)
{
return a.id < b.id;
}
int main()
{
int n, i, j, k, t, q, min, sum;
cin >> t;
while (t--)
{
mem(p);
cin >> n;
for (i = 0; i < n; ++i) scanf("%d%d", &(p[i].x), &(p[i].l)), p[i].cnt = 0, p[i].id = i;
sort(p, p + n);
for (i = n - 1; i >= 0; --i)
{
p[i].cnt = 1, p[i].l += p[i].x - 1;
for (j = i + 1; p[j].x <= p[i].l && j < n; ++j) p[i].cnt++, p[i].l = max(p[i].l, p[j].l);
}
sort(p, p + n, cmp);
for (i = 0; i < n; ++i) printf("%d ", p[i].cnt);
cout << endl;
}
return 0;
}
8:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(a) memset(a, 0, sizeof(a))
#define N 1000005
#define LL long long
#pragma warning (disable : 4996)
using namespace std;
int ql, qr, a[N], b[N], num[N], kill;
struct no
{
int cnt, l, r;
}n[4*N];
void bld(int x, int l, int r)
{
int m = (l + r) >> 1;
n[x].cnt = 0;
n[x].l = l;
n[x].r = r;
if (r == l) return ;
else bld(2* x, l, m), bld(2 * x + 1, m + 1, r);
}
void maint(int x, int l, int r)
{
int ls = x * 2, rs = 2 * x + 1, m = (l + r) >> 1;
if (l < r)
{
n[ls].cnt += n[x].cnt, n[rs].cnt += n[x].cnt;
maint(ls, l, m), maint(rs, m + 1, r);
}
else num[kill++] = n[x].cnt;
}
void upd(int x, int l, int r)
{
int m = (l + r) >> 1, ls = 2 * x, rs = 2 * x + 1;
if (l == r) n[x].cnt++;
else
{
if (ql <= l&& qr >= r) n[x].cnt++;
else
{
if (ql <= m) upd(ls, l, m);
if(qr > m) upd(rs, m + 1, r);
}
}
}
int main()
{
int nn, i, j, k, t, q;
LL re;
while (cin >> t)
{
mem(n), mem(num), kill = 0;
cin >> nn >> q;
for (i = 0; i < nn; ++i) cin >> a[i];
sort(a, a + nn);
bld(1, 1, nn);
for (i = 0; i < q; ++i)
{
cin >> ql >> qr;
upd(1, 1, nn);
}
maint(1, 1, nn);
sort(num, num + nn);
for (i = 0, re = 0; i < nn; ++i)
re += a[i] * num[i];
cout << re << endl;
}
return 0;
}
9:
#include<iostream>
#include<cstring>
#include<set>
#include<cstdio>
#pragma warning (disable : 4996)
using namespace std;
#define N 100005
struct po
{
int x, y;
bool operator < (const po &t) const
{
if (x != t.x) return x < t.x;
else return y < t.y;
}
}p[N];
set<po> a;
int main()
{
int n, i, j, k, x, y;
char s[10] = {0};
po tem;
set<po>:: iterator iter;
cin >> n;
while (n--)
{
scanf("%s%d%d", s, &(tem.x), &(tem.y));
if (s[0] == 'a')
{
if (!a.count(tem)) a.insert(tem);
}
else if (s[0] == 'e') a.erase(tem);
else
{
if (a.count(tem))
{
iter = a.find(tem);
iter++;
if (iter == a.end()) printf("-1\n");
else printf("%d %d\n", (*iter).x, (*iter).y);
}
else
{
a.insert(tem);
iter = a.find(tem);
iter++;
if (iter == a.end()) printf("-1\n");
else printf("%d %d\n", (*iter).x, (*iter).y);
a.erase(tem);
}
}
}
return 0;
}
10:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(a) memset(a, 0, sizeof(a))
#define N 100005
#define M 1000005
#define LL long long
#pragma warning (disable : 4996)
using namespace std;
int a[N];
int main()
{
int n, i, j, k, t, q, min, sum;
LL re;
cin >> t;
while (t--)
{
cin >> n;
for (i = 0, min = M, re = sum = 0; i < n; ++i) scanf("%d", a + i), min = min > a[i] ? a[i] : min, re ^= a[i], sum += a[i];
if (re == 0)
cout << sum - min << endl;
else cout << "NO\n";
}
return 0;
}
水到不能再水。。。。Orz