文章目录
前言
F. Fields Division
题意:存双向边的图,从n-1开始向前走,直到不能走为止,这条路为Bob的。没有经过的点是Alice的。
coding
void dfs(int x)
{
vis[x] = 1;
for(auto v : g[x])
{
if(v == n) continue;
if(!vis[v]) dfs(v);
}
}
void solve(){
IOS;
cin >> n >> m;
rep(i, m)
{
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(n - 1);
rep(i, n)
{
if(vis[i]) cout << 'B';
else cout << 'A';
}
}
H.待补
I. Invested Money
题意:给定今天是星期几和存了几天钱,以及每次存钱距离今天多少天。
每次存的钱都是30天定期,只有到期且是**周一到周五才能进行取钱或者是进行续存服务**
问:最近一次能够去到一次钱距离今天几天?
//代码最好简洁整齐,方便debug
思路:1->3->5->1
2->4->6->1
3->5->7->1
4->6->1
5->7->1
题目保证不会存款不会在周六周日
能够发现周期是1->3->5,那么处理完周期外的天数就能够按照周期进行了。
coding
int a[N];
void solve()
{
string s;
cin>>s;
int now=0;
if(s=="Mon")now=1;
else if(s=="Tue")now=2;
else if(s=="Wed")now=3;
else if(s=="Thu")now=4;
else if(s=="Fri")now=5;
else if(s=="Sat")now=6;
else if(s=="Sun")now=0;
int n;
scanf("%d",&n);
int ans=inf;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
int start=(now-a[i]%7+7)%7;
int flag=0;
if(a[i] == 0)flag=1;
if(start==2){
if(a[i]>=62){
a[i]-=62;
start=1;
}
else if(a[i]>=30){
a[i]-=30;
start=4;
}
}
else if(start==3){
if(a[i]>=61){
a[i]-=61;
start=1;
}
else if(a[i]>=30){
a[i]-=30;
start=5;
}
}
else if(start==4){
if(a[i]>=32){
a[i]-=32;
start=1;
}
}
else if(start==5){
if(a[i]>=31){
a[i]-=31;
start=1;
}
}
a[i]%=91;
while(a[i] > 0) {
if(start == 1) {
start = 3;
a[i] -= 30;
} else if(start == 2) {
start = 4;
a[i] -= 30;
} else if(start == 3) {
start = 5;
a[i] -= 30;
} else if(start == 4) {
start = 1;
a[i] -= 32;
} else if(start == 5) {
start = 1;
a[i] -=31;
}
}
if(flag) {
if(start == 5) a[i] =31;
else if(start == 4) a[i] = 32;
else a[i] = 30;
}
ans=min(ans,abs(a[i]));
}
printf("%d\n",ans);
}
Grittyb’s coding
//更简洁易懂些
int a[N];
int val[8], to[8];
int Anow=0;
string s;
void init() {
if(s=="Mon")Anow=1;
else if(s=="Tue")Anow=2;
else if(s=="Wed")Anow=3;
else if(s=="Thu")Anow=4;
else if(s=="Fri")Anow=5;
else if(s=="Sat")Anow=6;
else if(s=="Sun")Anow=7;
to[1] = 3, val[1] = 30;
to[2] = 4, val[2] = 30;
to[3] = 5, val[3] = 30;
to[4] = 1, val[4] = 32;
to[5] = 1, val[5] = 31;
}
int main(int argc, char const *argv[])
{
init_code();
cin>>s;
init();
int n;
scanf("%d",&n);
int ans=INF;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
int y = a[i] % 7;
int now = Anow;
if(now > y) now -= y;
else now = now + 7 - y;
int re = 0;
if(a[i] == 0) {
re = val[now];
} else {
while(now != 1 && re < a[i]) {
re += val[now];
now = to[now];
}
if(re < a[i])re += (a[i] - re) / 91 * 91;
while(re < a[i]) {
re += val[now];
now = to[now];
}
}
ans = min(ans, re - a[i]);
}
printf("%d\n",ans);
return 0;
}
J. Joining Pairs
题意:给定平面内的几条线段的两端点,将线段能够随意弯曲(平面内)
问:是否能够使得所有的线段不相交?
思路:如果线段的的两端点都在平面的边界上,那么平面一定会被分割成两个平面。
如果另一条线段的端点分别在两个平面的边界上,那么一定会产生交点,那么一定不符合条件。
显然绿色的会产生交点,而紫色的不会产生交点。
此当产生交点时可以看出如果我们按照一个顺序存放所有的端点,那么两条线段的端点会有前后顺序,利用括号匹配的写法进行同一线段匹配,最后判断栈是否为空就能够判断是否有交点了。
coding
//直接cin输入会T
vector<PII>up,dw,le,ri;
vector<int>all;
stack<int>st;
int h,w,n,cnt=0;
bool check(int a,int b)
{
if(a==0||a==h||b==0||b==w)return 1;
else return 0;
}
void add(int a,int b){
if(a==0)up.push_back({b,cnt});
else if(a==h)dw.push_back({b,cnt});
else if(b==0)le.push_back({a,cnt});
else if(b==w)ri.push_back({a,cnt});
}
void solve()
{
scanf("%d%d%d",&h,&w,&n);
for(int i=1;i<=n;i++){
int a1,b1,a2,b2;
scanf("%d %d %d %d",&a1,&b1,&a2,&b2);
if(check(a1,b1)&&check(a2,b2)){
cnt++;
add(a1,b1);
add(a2,b2);
}
}
sort(up.begin(),up.end());
sort(dw.begin(),dw.end());
sort(le.begin(),le.end());
sort(ri.begin(),ri.end());
for(int i=0;i<up.size();i++)
all.push_back(up[i].second);
for(int i=0;i<ri.size();i++)
all.push_back(ri[i].second);
for(int i=dw.size()-1;i>=0;i--)
all.push_back(dw[i].second);
for(int i=le.size()-1;i>=0;i--)
all.push_back(le[i].second);
for(int i=0;i<all.size();i++){
if(!st.empty()&&st.top()==all[i])st.pop();
else st.push(all[i]);
}
if(st.empty())printf("Y\n");
else printf("N\n");
}
K.KIARA is a Recursive Acronym
题意:只能用给定所有字符串的首字母,问能否组成给定字符串中的某一个字符串。
coding
//输入必须优化
void solve(){
IOS;
int n;
cin >> n;
rep(i, n)
{
cin >> s[i];
int k = s[i][0] - 'A';
a[k]++;
}
rep(i, n)
{
int f = 1;
for(int j = 0; j < s[i].size(); j++)
{
if(a[s[i][j] - 'A'] == 0){
f = 0;
break;
}
}
if(f)
{
printf("Y");
return;
}
}
printf("N");
}
M. Most Ordered Way
题意:有n个事件,每个事件有完成花费的时间和结束的最后期限
问:是否能够按时完成所有的事件,如果能完成使得完成的事件的字典序排列尽量小
思路:首先利用最后期限排序后特判是否能够按时完成所有事件
那么关键就是能够完成时找最小字典序排列,也就是并发执行事件时尽可能事件编号小的先进行。
直接O(n2)复杂度能过,而O(n2logn)不能过。
coding
struct thing{
int cost,deadline,idx;
}th[5100];
bool vis[5100];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>th[i].cost>>th[i].deadline;
th[i].idx=i;
}
sort(th+1,th+n+1,[](thing &a,thing &b){
return a.deadline<b.deadline;
});
ll sum=0;
for(int i=1;i<=n;i++){
if(sum+th[i].cost>th[i].deadline){
printf("*");
return;
}
sum+=th[i].cost;
}
ll now=0;
int num=n;
while(num>0){
int j=-1,maxn=1e9+1;
ll s2=now;
for(int i=1;i<=n;i++){
if(vis[i])continue;
if(maxn>=th[i].cost&&(j==-1||th[i].idx<th[j].idx))j=i;
s2+=th[i].cost;
maxn=min(maxn*1ll,th[i].deadline-s2);
}
now+=th[j].cost;
printf("%d ",th[j].idx);
num--;
vis[j]=1;
}
}