【浮*光】【Codeforces Round #482 (Div. 2)】 解题报告

咳咳因为我们老大觉得太简单了,所以这个只有自己做了qwq

两个小时的比赛,除去自己的智障、还有好多没学过的有点无奈==

第三题看了dalao的代码qaq,然后第五题实在没时间看...

A. Pizza, Pizza, Pizza!!!

#include <bits/stdc++.h>
using namespace std;
/*【平分披萨】
正好有n个Shiro的朋友在这里,要把披萨分成n+1份。
她希望切片的大小和形状完全一样,想用最少的直切来切披萨。
切是一个直的线段,它可能在披萨里面或外面结束。你能帮助Shiro解决这个问题吗?
分析》0≤n≤10^18 用longlong
根据蛋糕的对称性,当n为奇数时,需要切n刀才可
而当n为偶数时,只需要切n/2刀 [特判等于一的情况!!] */
int main(){
    long long n,ans=0; 
    cin>>n; n+=1;  
    if(n==1) n=0;//longlong类型的1 特判
    if(n%2==0) n/=2;//除二的过程中已经保留了分割的一刀 
    cout<<n<<endl;  
    return 0;
}

B. Treasure Hunt

#include <bits/stdc++.h>
using namespace std;
/*【寻宝游戏】
题意》给出三个字符串,表示三个人初始拥有的串。进行n次操作。
每次操作任意替换一个字母,问每串中{曾经出现的个数最多的相同的字符}谁更多。 
分析》找初始串个数最多的字母,其他的按全部步数转换成单个字母,
*注意*初始的字符串中即使是最多元素也不会计入统计,至少一次操作后才能记入,
所以需要特判 if(ans==len&&n==1) return len-1;  情况  */
const int inf=0x3f3f3f3f;  
int n,len,max1,max2,max3;  
void print(){  //输出赢家
    if(max1>max2&&max1>max3) cout<<"Kuro"<<endl;  
    else if(max2>max1&&max2>max3) cout<<"Shiro"<<endl;  
    else if(max3>max1&&max3>max2) cout<<"Katie"<<endl;  
    else cout<<"Draw"<<endl;  
}  
int work(){  
    char ss[200005]; scanf("%s",ss);
    int cnt[300]; memset(cnt,0,sizeof(cnt)); //统计字符个数
    int ans=-1,len=strlen(ss);
    for(int i=0;i<len;i++){  
        cnt[ss[i]]++; ans=max(ans,cnt[ss[i]]);  
    }  
    if(ans==len&&n==1) return len-1;//初始字符串是最多元素,但不会计入统计
    else if(len-ans>=n) return ans+n;//不能达到一整串完全相同
    else return len; //曾经有情况是一整串完全相同
}  
int main(){  
    scanf("%d",&n);  //n次变换
    max1=work(); max2=work(); max3=work(); print(); 
    return 0; 
}  


C. Kuro and Walking Route

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

/*【城镇道路】
题意》hss生活在Iceland,n个城镇都有n-1个连接别的城镇的双向道路。
jy会选择两个城镇(u,v)和从u到v的最短路径(注意,(u,v)被认为是不同于(v,u))。
在Iceland有两个特殊的城镇,叫做Florence(用索引x来表示)<--坠喜欢的城市!!!
和hangzhou(用索引y表示)。Florence是一个有许多强烈气味的花的城镇,
而hangzhou是另一个有许多蜜蜂居住的城镇。特别是,如果从u到v的路径上,
当jy到达了Florence后,他就会到达hangzhou,Kuro想知道他可以选择多少个城市(u,v)。
既然他不是很聪明(??),他请你帮他解决这个问题。//这个题意实在无能为力...
题意简化》给定一个n个点,n-1条边的无向图,途中任意两点联通,
并给出节点x,y,计算图上两点(u,v)之间的最短路径依次经过x,y的对数,
(u,v)与(v,u)视作不同一对,求总对数-符合条件的对数 */

//以下是来自 https://blog.csdn.net/WangYC123456/article/details/80318442 的分析和代码
/*分析》无向图,可以将图中任意节点作为根建树->将y作为树根,x则是树y的某一节点
设s[i]为{子树i的size(包括i本身)},节点z为(y,x)路径上y的儿子节点  //↓↓↓用树的数量大小表示方案数
符合条件的对数为(y,x)路径两端的节点数相乘,即s[x]*(s[y]-s[z]),用n(n-1)减去就可以得出答案(longlong)
//邻接表存图,s[]用递归的dfs完成,寻找而节点z同样用dfs的递归标记  */

#define ll long long  
const int MAXN=3e5+10;  
int n,x,y,z;  
int last[MAXN],num;  
int size[MAXN];  
bool tag[MAXN],vis[MAXN];  

inline int in(){  //读入优化
    int x=0,flag=1;  
    char ch=getchar();  
    while(ch<'0'||ch>'9'){ if(ch=='-') flag=-1; ch=getchar(); }  
    while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } 
    return x*flag;  
}  

struct Edge {  //邻接表
    int nex,to;  
}e[MAXN*2];  
void adds(int from,int to){ //建边
    e[++num]=(Edge){last[from],to};  
    last[from]=num;  
}  

int dfs(int u){  
    vis[u]=true; size[u]++;  
    if(u==x) tag[u]=true; 
    for(int i=last[u];i;i=e[i].nex){  
        int v=e[i].to;  //下一条边
        if (!vis[v]){  
            dfs(v); size[u]+=size[v];  //子树值合并
            if(tag[v]){ tag[u]=1; if(u==y) z=v; } 
        //个人理解:v=x才为true,u=y则这条路为x->y,z为子树节点 
        }  
    }  
}  

int main(){  
    n=in(); x=in(); y=in();  
    for(int i=1;i<n;i++)
    {  
        int u=in(),v=in();  
        adds(u,v); adds(v,u);  
    }  
    dfs(y); cout<<(ll)n*(n-1)-(ll)size[x]*(size[y]-size[z])<<endl;  
    return 0;  
}  


D. Kuro and GCD and XOR and SUM

http://codeforces.com/contest/979/problem/D

#include <bits/stdc++.h>
using namespace std;
/*【数学游戏】
游戏关于最大公约数(GCD),XOR值和两个数字的和。
jy非常喜欢这款游戏,所以他每天都会按照级别解决问题。
他今天休假(过生日去辣~\(≧▽≦)/~)无法继续自己的连胜。
由于hss是一个可靠的人,jy请她在这天来他家玩游戏。
最初,有一个空阵列a。游戏由两种类型的q任务组成。
第一种类型要求hss给a添加一个数字ui。
第二种类型要求hss找到一个存在的数v,满足ki|GCD(xi,v),xi+v≤si;且使xi⊕v最大,
其中⊕表示按位[异或运算],GCD(c,d )表示最大公约数,y|x表示x可以被y整除。
如果没有找到这样的数字,则报告-1。
hss要自动准确地完成游戏中的任务,以满足她亲爱的jy。  */

/*【题意简析】
有n个操作,操作1代表往集合里面加入一个数字x,
操作2会给出三个数字x,k,s,然后对于每一个2操作,要求从集合中找一个数v,
满足下面的条件:gcd(x,v)%k==0  v≤s-x , 使x⊕v的值最大。
1.gcd(x,v)%k==0,那么必然有x%k==0和v%k==0,首先判断一下x%k成立与否。
2.01字典树可以很容易找出一堆数里面于一个数{异或值最大}的数(0找1,1找0),
又因为当k==1的时候gcd(x,v)%k==0,这个条件一定满足,
所以问题转化成从集合中找出小于等于s-x范围内的异或值最大的数。
(用minn[]数组标记字典树中当前节点插入进来的最小值)
3.k!=1时,v一定是k的倍数,在s−x范围内{枚举k的倍数},不断更新答案。 */

//首先某蒟蒻表示自己并没有学过字典树qaq
//思路和代码来自 https://blog.csdn.net/riba2534/article/details/80344026 感谢dalao

#define mem(a, b) memset(a, b, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define inf 0x3f3f3f3f
typedef long long ll;
const int N = 2e5 + 10;
int a[N];
struct dicTree{
    struct node{
        int next[2];
    } tree[N * 32];
    int minn[N]; //记录当前节点插入进来的最小的值
    int root, sz;
    int newnode(){
        tree[sz].next[0] = tree[sz].next[1] = -1;
        sz++;
        return sz - 1;
    }
    void init(){
        sz = 0;
        mem(minn, inf);
        root = newnode();
    }
    void insert(int x){
        int p = x;
        int now = root;
        minn[now] = min(minn[now], p);
        for (int i = 31; i >= 0; i--){
            int to = (x >> i) & 1;
            if (tree[now].next[to] == -1)
                tree[now].next[to] = newnode();
            now = tree[now].next[to];
            minn[now] = min(minn[now], p);
        }
    }
    int find(int x, int p){
        int now = root;
        if (minn[now] > p)
            return -1;
        for (int i = 31; i >= 0; i--){
            int to = (x >> i) & 1;
            if (tree[now].next[to ^ 1] != -1 
                  && minn[tree[now].next[to ^ 1]] <= p)
                to ^= 1;
            now = tree[now].next[to];
        }
        return minn[now];
    }
} ac;
int main(){
    //freopen("in.txt", "r", stdin);
    int t, op, x, k, s;
    ac.init();
    scanf("%d", &t); while (t--){
        scanf("%d", &op);
        if (op == 1){
            scanf("%d", &x); a[x] = 1;
            ac.insert(x);
        }
        else{
            scanf("%d%d%d", &x, &k, &s);
            if (x % k != 0){
                puts("-1"); continue;
            }
            if (k == 1){
                printf("%d\n", ac.find(x, s - x));
                continue;
            }
            int maxx = -1, ans = -1;
            for (int v = k; v <= s - x; v += k)
                if (a[v] && (v ^ x) > maxx) {
                    maxx = v ^ x; ans = v;
                }
            printf("%d\n", ans);
        }
    }
    return 0;
}

/* //来自同一位大佬的集合set做法(这个我也不会就不多说了w)
#define mem(a, b) memset(a, b, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define inf 0x3f3f3f3f
typedef long long ll;
const int N = 1e5 + 10;
set<int> se[N];
int main(){
    // freopen("in.txt", "r", stdin);
    int n, op, x, k, s;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        scanf("%d", &op);
        if (op == 1){
            scanf("%d", &x);
            for (int i = 1; i <= (int)sqrt(x); i++)
                if (x % i == 0)
                {
                    se[i].insert(x);
                    se[x / i].insert(x);
                }
        }
        else{
            scanf("%d%d%d", &x, &k, &s);
            int sum = -1, ans = -1;
            if (x % k){
                printf("%d\n", ans); continue;
            }
            auto it = se[k].upper_bound(s - x);
            if (se[k].empty() || it == se[k].begin()){
                printf("%d\n", ans);
                continue;
            }
            --it;
            for (; it != se[k].begin(); --it){
                int v = *it;
                if (sum > x + v) break;
                if (sum < (x ^ v)){
                    ans = v; sum = x ^ v;
                }
            }
            if (sum < (x ^ *it))  ans = *it;
            printf("%d\n", ans);
        }
    }
    return 0;
}  */


E. Kuro and Topological Parity

http://codeforces.com/contest/979/problem/E

/* 【E. Kuro and Topological Parity】 
Kuro向Katie提出挑战,只用白纸,铅笔,一把剪刀和许多箭头来制作(箭的数量无限)
纸分成n份,Shiro用某种颜色画了一些作品。具体来说,第i部分具有颜色ci,
其中ci = 0定义黑色,ci = 1定义白色,ci = -1意味着这件作品还没有被着色。
游戏的规则:玩家必须在一对不同的棋子之间放置一些箭头,这样每个箭头的起始数字小于棋子的数量。
另外,两个不同的部件只能通过最多一个箭头连接。之后,玩家必须选择颜色(0或1)为每个未上漆的作品。
将箭头和着色片段的有效方式的分数定义为交替颜色片段的数量。例如,[1→0→1→0],[0→1→0→1],[1],[0]是有效路径并将被计数。
只有当从x到y有一个箭头时,你才能从x片段到y片段。
设定奇偶校验p,其中p = 0代表“偶数”,p = 1代表“奇数”,以这样的方式放置箭头并选择颜色。
好像会有很多满足Kuro的方法。他想计算它们的数量,但这可能是一个非常大的数字。
让我们来帮助他解决他的问题,但打印它的模109+7 ,游戏如此之多,以至于他一天一天地解决关卡问题。
可悲的是,他正在休假一天,他无法继续自己的连胜。由于凯蒂是一个可靠的人,Kuro请她在这天来他家玩游戏。
最初,有一个空阵列a。游戏由两种类型的q任务组成。第一种类型要求凯蒂给a添加一个数字ui。
第二种类型要求凯蒂找到一个存在的数v,使得kiGCD(xi,v),xi +v≤si和xi⊕v被最大化,
其中⊕表示按位异或运算,GCD(c,d )表示整数c和d的最大公约数,y | x表示x可以被y整除
如果没有找到这样的数字,则报告-1。  */  //这个题考试的时候只有不到100的正确数,等我有时间再想吧qaq


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

猜你喜欢

转载自blog.csdn.net/flora715/article/details/80375503
今日推荐