【浮*光】【Codeforces Round #492 (Div. 2)】A,B,C,D,E 【C.Tesla】

【A. Hit the Lottery】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/*【A. Hit the Lottery】
有n元钱(!),面值为1,5,10,20,100,求最少的纸币数目。 */

int main(){
    int n,ans=0; scanf("%d",&n);
    ans+=n%5; n-=n%5; 
    ans+=(n%10)/5; n-=n%10;
    ans+=(n%20)/10; n-=n%20;
    ans+=(n%100)/20; n-=n%100;
    ans+=n/100;
    printf("%d\n",ans);
    return 0;
}

【B. World Cup】

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/*【B. World Cup】
有n个入口。在第i个入口前面有ai人。
每个入口允许其队列中的一个人在一分钟内进入。
Allen使用以下策略进入:1.最初,他站在第一个入口前排队的尽头。
2.每一分钟,如果他在一分钟内不被允许进入(意味着他不是队列中的第一个),
他离开当前队列并站在下一个入口(离开了最后一个入口后进入第一个入口)。
确定艾伦最终进入的入口。  */

int a[100009];

int main(){
    int n; cin>>n; int min_=1e9+10;
    for(int i=0;i<n;i++) cin>>a[i],min_=min(min_,a[i]);
    int lazy=min_; //lazy标记
    int t=min_; t%=n;
    while(1){
        if(a[t]-lazy<=0){ cout<<t+1<<endl; return 0;}
        else lazy++;
        t++; t%=n;
    }
    return 0;
}

【C.Tesla】

4*n停车场,第二行和第三行是过道,第一行和第四行是车库,0表示空地。

在过道的车可以上下左右四个方向随意走动,车一旦进入第一和第四行就不能动了。

现在有k辆车(1~k)要停车,编号为 i 的车要停入编号为 i 的车库,保证车和车库的编号都只有一个。

一辆车移动一下算一步,现在要把所有的车入库,请你输出一种20000步以内的解法,没有输出-1。


思路 //来自 https://blog.csdn.net/ZscDst/article/details/80821376

我们让这些车在第二行和第三行兜圈子走,如果哪个车可以停入对应的车库就让他停进去,其他的继续。

如果初始状态下,所有车都停不进去且没有空位,那么就无解。

一旦有一个空位可以用于挪动车辆,我们照此方法就可以把所有车停进去。

最坏情况下每个车都移动了一圈才停进去,移动次数为100*100+100,所以方案可行。 

这里写图片描述
接下来就是个大模拟了…
把第二行和第三行对接到了一起(按照图中转圈方向),第一行和第四行按照同样的方法对接到一起。
比如第一个样例:
4 5
1 2 0 4
1 2 0 4
5 0 0 3
0 5 0 3
变为:
2 10
1 2 0 4 3 0 5 0
1 2 0 4 3 0 0 5
这样的话第一行就是车库,第二行就是车所在的过道。
对于第一行第i个位置,如果 i/n=0 证明在第一列的 i%n+1 位置,否则就是在第四列的倒数 i%n+1 位置。
对于第二行第i个位置,如果 i/n=0 证明在第二列的 i%n+1 位置,否则就是在第三列的倒数 i%n+1 位置。
我们把第二行和第三行中的车和空地理解成一列火车在旋转,车头为一个空地,每次后面的车厢都往前走了一节。
这里写图片描述
在变换后的数组中其实就是每个数字都往后面移动了一位,最后一位变为第一位。

但是,顺序是红色箭头,黑色的箭头,绿色箭头。一直旋转停车,直到所有车都入库,

过程中如果是车的移动就用ans记录下路径。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 205;
int n, k, a[5][MAXN], s;//s是火车头
struct Node
{
    int id, x, y;
    Node(int id, int x, int y): id(id), x(x), y(y) {}
};
vector<Node> ans;
void park()//尝试停车
{
    for (int i = 0; i < 2*n; i++) if (a[1][i] && a[1][i] == a[0][i])
    {//入库,记录路径
        ans.push_back(Node(a[1][i], i/n?4:1, i%n+1));
        a[1][i] = 0; k--;
    }
}
bool judge()//有解?
{
    park();
    for (int i = 0; i < 2*n; i++) if (!a[1][i]) return true;
    return false;
}
void turn()
{
    vector<Node> v1, v2;
    int t = a[1][2*n-1];
    for (int i = 2*n-1; i >= 1; i--)
    {
        a[1][i] = a[1][i-1];
        if (a[1][i])//是车的移动,记录路径
        {
            if (i > s) v1.push_back(Node(a[1][i], i/n?3:2, i%n+1));//绿色箭头
            else v2.push_back(Node(a[1][i], i/n?3:2, i%n+1));//红黑箭头
        }
    }
    a[1][0] = t; if (t) v2.push_back(Node(t, 2, 1));
    for (auto i: v2) ans.push_back(i);//红黑箭头
    for (auto i: v1) ans.push_back(i);//绿色箭头
}
int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; i++) scanf("%d", &a[0][i]);
    for (int i = 0; i < n; i++) scanf("%d", &a[1][i]);
    for (int i = 2*n-1; i >= n; i--) scanf("%d", &a[1][i]);
    for (int i = 2*n-1; i >= n; i--) scanf("%d", &a[0][i]);

    if (!judge()) { printf("-1\n"); return 0; } //判断无解
    for (int i = 0; i < 2*n; i++) if(!a[1][i]) { s = i; break; } //找火车头

    while (k)
    {
        turn(); park();//旋转,尝试停车
        s = (s+1)%(2*n);
    }
    printf("%d\n", ans.size());
    for (auto i: ans)
    {
        if (i.x == 3 || i.x == 4) i.y = n-i.y+1;//倒数变正数
        printf("%d %d %d\n", i.id, i.x, i.y);
    }
    return 0;
}
/*
4 5
1 2 0 4
1 2 0 4
5 0 0 3
0 5 0 3
*/

【D. Suit and Tie】

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/*【D. Suit and Tie】
给你2*n个数,把相同的数放在一起最小需要移动多少次位置。 */

//贪心,每次找和自己相同的数的位置,中间已访问的数记为-1,不再访问。
//加{ 每次找到的位置减去数自己的位置减去一 }, 再减{ 中间已经被找到的数 }。

int a[209],okk[209];

int main(){
    int n,ans=0; scanf("%d",&n);
    for(int i=1;i<=2*n;i++) scanf("%d",&a[i]);
    for(int i=1;i<2*n;i++)
      if(okk[i]!=-1)
        for(int j=i+1;j<=2*n;j++){
            if(okk[j]==-1) ans-=1; //已经配对的
            if(a[i]==a[j]){
                okk[i]=-1; okk[j]=-1;
                ans+=j-i-1;
                break;
            }
        }
    cout<<ans<<endl;
    return 0;
}


【E. Leaving the Bar】

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/*【E. Leaving the Bar】
给定一些向量,你可以改变它的符号,使得这些向量之和的长度小于1.5e6。
【分析】可以将速度分解成为x,y轴方向上的分量,每次贪心取最小,
因为每次我贪心原则是一样的,最后的结果有可能大于1.5e6 ,我们需要加一些随机性,
多次贪心,直到结果满足题意。正解是每三个向量中都能找到两个向量合起来 <= 1e6,
然后不断合并,最后只会剩下一个或者两个向量,如果一个向量肯定 <= 1e6, 
如果是两个向量一定 <= 1.5 * 1e6。 */

const int maxn = 1e5 + 100;

struct node {
    int id;
    ll x, y;
} data[maxn];

int ans[maxn];

int main() {
    srand(time(NULL));
    int n; scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        cin>>data[i].x>>data[i].y;
        data[i].id = i;
    }
    while(true) {
        ll tmp = 0, t1, t2;
        ll prex = data[1].x, prey = data[1].y;
        ans[data[1].id] = 1;
        for(int i = 2; i <= n; i++) {
            ll tx1 = prex - data[i].x;
            ll ty1 = prey - data[i].y;
            t1 = tx1 * tx1 + ty1 * ty1;

            ll tx2 = data[i].x + prex;
            ll ty2 = data[i].y + prey;
            t2 = tx2 * tx2 + ty2 * ty2;

            if(t1 < t2) {
                ans[data[i].id] = -1;
                prex = tx1; prey = ty1;
            }
            else {
                ans[data[i].id] = 1;
                prex = tx2;
                prey = ty2;
            }
        }
        if(min(t1, t2) <= 2250000000000LL) 
            break;
        else random_shuffle(data + 1, data + n + 1);
    }
    for(int i = 1; i <= n; i++)
        printf("%d%c", ans[i], i == n ? '\n' : ' ');
    return 0;
}

                                                                                ——时间划过风的轨迹,那个少年,还在等你。

4*n停车场,第二行和第三行是过道,第一行和第四行是车库,0表示空地。

在过道的车可以上下左右四个方向随意走动,车一旦进入第一和第四行就不能动了。

现在有k辆车(1~k)要停车,编号为 i 的车要停入编号为 i 的车库,保证车和车库的编号都只有一个。

一辆车移动一下算一步,现在要把所有的车入库,请你输出一种20000步以内的解法,没有输出-1。


思路 //来自 https://blog.csdn.net/ZscDst/article/details/80821376

我们让这些车在第二行和第三行兜圈子走,如果哪个车可以停入对应的车库就让他停进去,其他的继续。

如果初始状态下,所有车都停不进去且没有空位,那么就无解。

一旦有一个空位可以用于挪动车辆,我们照此方法就可以把所有车停进去。

最坏情况下每个车都移动了一圈才停进去,移动次数为100*100+100,所以方案可行。 

这里写图片描述
接下来就是个大模拟了…
把第二行和第三行对接到了一起(按照图中转圈方向),第一行和第四行按照同样的方法对接到一起。
比如第一个样例:
4 5
1 2 0 4
1 2 0 4
5 0 0 3
0 5 0 3
变为:
2 10
1 2 0 4 3 0 5 0
1 2 0 4 3 0 0 5
这样的话第一行就是车库,第二行就是车所在的过道。
对于第一行第i个位置,如果 i/n=0 证明在第一列的 i%n+1 位置,否则就是在第四列的倒数 i%n+1 位置。
对于第二行第i个位置,如果 i/n=0 证明在第二列的 i%n+1 位置,否则就是在第三列的倒数 i%n+1 位置。
我们把第二行和第三行中的车和空地理解成一列火车在旋转,车头为一个空地,每次后面的车厢都往前走了一节。
这里写图片描述
在变换后的数组中其实就是每个数字都往后面移动了一位,最后一位变为第一位。

但是,顺序是红色箭头,黑色的箭头,绿色箭头。一直旋转停车,直到所有车都入库,

过程中如果是车的移动就用ans记录下路径。

猜你喜欢

转载自blog.csdn.net/flora715/article/details/81002225