T1:環
題解:
解法一:
- 觀察B操作相當於把1之間的0的個數其中一個+1,後一個-1,1循環代表0的個數也是循環的。根據循環對應關係畫一畫可以得出0的個數只能有2種,削去小的那部分,剩下的問題轉化爲了子問題(子問題的答案反過來再加上小的部分的0,就是當前0的個數的可行解)。那麼,當時無解。
最後得出第一行之後枚舉循環長度,再枚舉交換的位置,判斷是否可行即可,。
解法二
Code1:
#include<bits/stdc++.h>
#define maxn 105
using namespace std;
int T,n,k,l,a[maxn][maxn],b[maxn];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
void solve(int n,int k){
if(k==1) {a[0][0]=1;return;}
solve(k,n%k);
for(int i=0;i<k;i++) b[i]=a[0][k-i-1]+(n-k)/k;
for(int i=0;i<n;i++) a[0][i]=0;
for(int i=0,sum=0;i<k;i++)
a[0][i+sum]=1,sum+=b[i];
}
int main()
{
freopen("circle.in","r",stdin);
freopen("circle.out","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&k,&l);
if(gcd(n,k)!=1) {puts("NO");continue;}
for(int i=0;i<n;i++) a[0][i]=0;
solve(n,k);
for(int i=0;i<l-1;i++)
for(int t=1;t<n;t++){
for(int j=0;j<n;j++) a[i+1][(j+t)%n]=a[i][j];
int num=0,x,y;
for(int j=0;j<n&&num<=2;j++) if(a[i][j]!=a[i+1][j]){
num++;
if(num==1) x=j;
else y=j;
}
if(num==2){
if(x+1==y&&a[i][x]==1&&a[i][y]==0) break;
if(x==0&&y==n-1&&a[i][y]==1&&a[i][x]==0) break;
}
}
puts("YES");
for(int i=0;i<l;i++,putchar('\n'))
for(int j=0;j<n;j++) putchar(a[i][j]+'0');
}
}
Code2:
#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;
}
T2:DNA序列
題解:
首先,如果知道字符串的最優連接順序,那麼我們從後往前枚舉每個字符串的前綴,貪心取最優即可。
Code1(std):
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
string s[55], x[55], z[55];
int n, idx[55];
bool cmp(int a, int b)
{
if (x[a] == x[b])
return z[a] < z[b];
return x[a] > x[b];
}
int main()
{
freopen("dna.in", "r", stdin);
freopen("dna.out", "w", stdout);
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
cin >> s[i];
x[i] = s[i];
z[i] = "";
int t = s[i].length();
for (int j = 1; j <= t; j++)
{
string now = s[i].substr(0, j);
string res = s[i].substr(j);
int flg = 0;
while (1)
{
if (now > res)
{
flg = 1;
break;
}
if (res.substr(0, j) == now)
res = res.substr(j);
else
break;
}
if (!flg)
{
x[i] = now;
z[i] = res;
break;
}
}
string now = "";
while (now.size() <= 50)
now += x[i];
now = now.substr(0, 50);
x[i] = now;
z[i] += 'Z';
}
for (int i = 1; i <= n; i++)
idx[i] = i;
sort(idx + 1, idx + n + 1, cmp);
string ans;
for (int i = 1; i <= n; i++)
{
string lst = ans;
ans = "Z";
int t = s[idx[i]].size();
for (int k = 1; k <= t; k++)
ans = min(ans, s[idx[i]].substr(0, k) + lst);
}
cout << ans << endl;
}
還有個非常驚人的超級排序貪心,直接枚舉兩個字符串,看交換之後得到的答案是否更優:
#include<bits/stdc++.h>
#define maxn 55
using namespace std;
int n;
string a[maxn],ans;
string solve(){
string ret;
for(int i=n;i>=1;i--){
string now,mn="Z";
for(int j=0,lim=a[i].size();j<lim;j++)
now+=a[i][j],mn=min(mn,now+ret);
ret=mn;
}
return ret;
}
int main()
{
freopen("dna.in","r",stdin);
freopen("dna.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
ans=solve();
for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++){
swap(a[i],a[j]);
string tmp=solve();
if(tmp<ans) ans=tmp;
else swap(a[i],a[j]);
}
cout<<ans<<endl;
}
T3:探尋
樹上每個點上有一隻怪獸,打第只怪獸會減少的血量,打完之後會回覆的血量,要打它必須先打它的父親,在打的過程中必須時刻保證血量。問如果要打第只怪獸,初始時最少需要多少血量。
題解:
解法一:
- 這題就是這個題加上了一個目標點。
- 相當於讓,然後要求打完所有怪獸。
解法二:
Code1:
#include<bits/stdc++.h>
#define maxn 200005
#define LL long long
using namespace std;
const LL inf = 1ll<<49;
int n,fa[maxn];
bool del[maxn];
LL a[maxn],b[maxn],ans,sum;
struct cmp{
bool operator () (const int i,const int j)const{
bool f1=a[i]<b[i],f2=a[j]<b[j];
if(f1^f2) return f1;
if(f1) return a[i]==a[j]?i<j:a[i]<a[j];
return b[i]==b[j]?i<j:b[i]>b[j];
}
};
set<int,cmp>S;
int find(int x){return del[fa[x]]?fa[x]=find(fa[x]):fa[x];}
int main()
{
freopen("prospecting.in","r",stdin);
freopen("prospecting.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%lld%lld",&fa[i],&b[i],&a[i]);
if(b[i]==-1) b[i]=1ll<<50;
S.insert(i);
}
for(int x;sum<inf;S.erase(x),del[x]=1)
if(!find(x=*S.begin())){
ans=min(ans,sum-a[x]);
sum+=-a[x]+b[x];
}
else{
S.erase(fa[x]);
a[fa[x]]+=max(a[x]-b[fa[x]],0ll);
b[fa[x]]=b[x]+max(b[fa[x]]-a[x],0ll);
S.insert(fa[x]);
}
printf("%lld\n",-ans);
}
Code2(std):
#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;
}