T1
题解
先看看标算
代码超级短:
#include <bits/stdc++.h>
using namespace std;
#define REP(i, a, b) for (int i = (a), i##_end_ = (b); i < i##_end_; ++i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define x first
#define y second
#define pb push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()
template<typename T> inline bool chkmin(T &a, const T &b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
typedef long long LL;
const int oo = 0x3f3f3f3f;
const int maxn = 110;
int n, K, l;
int main()
{
freopen("circle.in", "r", stdin);
freopen("circle.out", "w", stdout);
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &n, &K, &l);
int inv = -1;
REP(i, 1, n)
if (K * i % n == 1)
{
inv = i;
break;
}
if (~inv)
{
puts("YES");
REP(i, 0, l)
{
static int tmp[maxn + 5];
memset(tmp, 0, sizeof tmp);
REP(j, 0, K) tmp[(i + j) * inv % n] = 1;
REP(j, 0, n) printf("%d", tmp[j]);
printf("\n");
}
}
else puts("NO");
}
return 0;
}
我的想法是这样:
考虑把01序列变为记录每个1之前有多少个0的序列,这样序列长度从n变为k,然后对于新序列,A类型操作是要求序列循环同构,B类型操作相当于把某个数-1,它后面的数+1,然后如果执行了B操作之后还能执行A操作,说明序列元素差不会超过1.然后可以把所有元素减去n/k,然后变为01序列,变成了子问题.直接递归计算。
无解情况:gcd(n,k)!=1
整个算法相当于暴力枚举+递归。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
int a[MAXN][MAXN], l, b[MAXN];
void solve(int n, int k) {
if(k == 1) {
for(int i = 1; i <= l; ++i) a[i][i%n] = 1;
return;
}
solve(k, n % k);
int bs = n / k;
for(int i = 0; i < k; ++i) b[i] = a[1][i];
for(int now = 0, i = 0; i < k; ++i) {
for(int j = now; j < now+bs+b[i]; ++j)
a[1][j] = 0;
a[1][now+bs+b[i]-1] = 1;
now += bs+b[i];
}
for(int i = 2, tmp; i <= l; ++i) {
tmp = 0;
while(++tmp < n) {
for(int j = 0; j < n; ++j) a[i][j] = a[i-1][(j+tmp)%n];
int cnt = 0, p1 = 0, p2 = 0;
for(int j = 0; j < n; ++j) {
if(a[i][j] != a[i-1][j]) {
++cnt;
if(cnt == 1) p1 = j;
if(cnt == 2) p2 = j;
}
if(cnt > 2) break;
}
if(cnt == 2 && ((a[i][p1] == 0 && a[i][p2] == 1 && p2-p1 == 1) || (a[i][p1] == 1 && a[i][p2] == 0 && p1 == 0 && p2 == n-1))) break;
}
}
}
int n, k;
int main () {
freopen("circle.in", "r", stdin);
freopen("circle.out", "w", stdout);
int T; scanf("%d", &T);
while(T--) {
scanf("%d%d%d", &n, &k, &l);
if(__gcd(n, k) > 1) { puts("NO"); continue; }
memset(a, 0, sizeof a);
solve(n, k); puts("YES");
for(int i = 1; i <= l; puts(""), ++i)
for(int j = 0; j < n; ++j)
printf("%d", a[i][j]);
}
}
T2
直接上题解
就是按照最优前缀排序后贪心计算。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 55;
int n, p[MAXN], id[MAXN];
string s[MAXN], c[MAXN];
int fc(int i, int j) {
string a = c[i], b = c[j];
while(a.size() != b.size()) {
if(a.size() < b.size()) a = a + c[i];
else b = b + c[j];
}
return a < b ? -1 : b < a ? 1 : 0;
}
bool cmp(int i, int j) {
int tmp = fc(i, j);
return tmp ? tmp == -1 : s[i].substr(p[i])+'U' > s[j].substr(p[j])+'U';
}
int main () {
freopen("dna.in", "r", stdin);
freopen("dna.out", "w", stdout);
cin>>n;
for(int i = 1; i <= n; ++i) cin>>s[i];
for(int i = 1; i <= n; ++i) {
int len = s[i].size();
for(int j = 1; j <= len; ++j) {
bool flg = 1;
for(int k = j; k < len; ++k) {
if(s[i][k%j] < s[i][k]) { flg = 1; break; }
if(s[i][k%j] > s[i][k]) { flg = 0; break; }
}
if(flg) { c[i] = s[i].substr(0, j); break; }
}
if(!c[i].size()) c[i] = s[i];
int L = c[i].size();
for(int j = L; j < len; j += L)
if(c[i] != s[i].substr(j, L)) { p[i] = j; break; }
if(!p[i]) p[i] = len;
id[i] = i;
}
sort(id + 1, id + n + 1, cmp);
string mn, now, ans; ans = s[id[n]][0];
for(int i = n-1, j, len, p; i; --i) {
now = mn = s[id[i]][p=0] + ans;
len = s[id[i]].size();
for(j = 1; j < len; ++j) {
now = ans;
for(int k = j; k >= 0; --k) now = s[id[i]][k] + now;
if(now < mn) mn = now, p = j;
}
while(~p) ans = s[id[i]][p--] + ans;
}
cout<<ans<<endl;
}
T3
难点在于读题。
#include <bits/stdc++.h>
using namespace std;
#define REP(i, a, b) for (int i = (a), i##_end_ = (b); i < i##_end_; ++i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define mp make_pair
#define x first
#define y second
#define pb push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()
template<typename T> inline bool chkmin(T &a, const T &b) { return b < a ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
typedef long long LL;
const int oo = 0x3f3f3f3f;
const int __buffsize = 100000;
char __buff[__buffsize];
char *__buffs, *__buffe;
#define getc() (__buffs == __buffe ? fread(__buff, 1, __buffsize, stdin), __buffe = __buff + __buffsize, *((__buffs = __buff)++) : *(__buffs++))
template<typename T> inline T &Read(T &x)
{
static char c;
while (1)
{
c = getc();
if (c == '-' || (c >= '0' && c <= '9')) break;
}
bool flag = c == '-';
x = flag ? 0 : c - '0';
while (1)
{
c = getc();
if (c < '0' || c > '9') break;
(x *= 10) += c - '0';
}
if (flag) x = -x;
return x;
}
#undef getc
const int maxn = 200100;
const LL maxsum = 1e17;
int n;
vector<int> children[maxn + 5];
LL gain[maxn + 5];
LL loss[maxn + 5];
int fa[maxn + 5];
multiset<pair<LL, LL> > all[maxn + 5];
void dfs(int x)
{
for (auto y : children[x])
{
dfs(y);
if (SZ(all[y]) > SZ(all[x])) swap(all[x], all[y]);
for (auto u : all[y]) all[x].insert(u);
all[y].clear();
}
LL cur_invest = loss[x], cur_profit = gain[x] - loss[x];
while (!all[x].empty() && (cur_profit <= 0 || cur_invest + cur_profit >= all[x].begin()->x))
{
auto tmp = all[x].begin();
cur_invest += max(0ll, tmp->x - (cur_invest + cur_profit));
cur_profit += tmp->y;
all[x].erase(tmp);
}
if (cur_profit > 0) all[x].insert(mp(cur_invest, cur_profit));
}
int main()
{
freopen("prospecting.in", "r", stdin);
freopen("prospecting.out", "w", stdout);
Read(n);
loss[0] = maxsum;
REP(i, 1, n)
{
Read(fa[i]);
Read(gain[i]);
Read(loss[i]);
children[fa[i]].pb(i);
if (!~gain[i]) gain[i] = maxsum * 2;
}
dfs(0);
printf("%lld\n", all[0].begin()->x - maxsum);
return 0;
}