首页 > 代码库 > cf#263 div2 解题报告
cf#263 div2 解题报告
A:要求是否全部的字符都挨着偶数个‘o‘,要读题啊....各种读错题...
#include <cstdio>using namespace std;char maz[101][101];int n;int cnt[101][101];const int dx[4]={0,0,-1,1};const int dy[4]={1,-1,0,0};int main(){ scanf("%d",&n); gets(maz[0]); for(int i=0;i<n;i++){ gets(maz[i]); } for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(maz[i][j]==‘o‘){ for(int k=0;k<4;k++){ int nx=i+dx[k]; int ny=j+dy[k]; if(nx<n&&ny<n&&nx>=0&&ny>=0){cnt[nx][ny]++;} } } } } for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(cnt[i][j]&1){puts("NO");return 0;} } } puts("YES"); return 0;}
B:贪心,要读题啊!,数组开小了结果Bcha了,
#include <cstdio>#include <algorithm>using namespace std;long long n,k;long long cnt[26];char maz[200001];int main(){ scanf("%I64d%I64d",&n,&k); gets(maz); gets(maz); for(int i=0;i<n;i++)cnt[maz[i]-‘A‘]++; sort(cnt,cnt+26); long long ans=0; for(int i=25;i>=0;i--){ if(cnt[i]>=k){ ans+=k*k; k=0; } else { k-=cnt[i]; ans+=cnt[i]*cnt[i]; } if(k==0)break; } printf("%I64d\n",ans); return 0;}
C:
Appleman and Toastman play a game. Initially Appleman gives one group of n numbers to the Toastman, then they start to complete the following tasks:
- Each time Toastman gets a group of numbers, he sums up all the numbers and adds this sum to the score. Then he gives the group to the Appleman.
- Each time Appleman gets a group consisting of a single number, he throws this group out. Each time Appleman gets a group consisting of more than one number, he splits the group into two non-empty groups (he can do it in any way) and gives each of them to Toastman.
After guys complete all the tasks they look at the score value. What is the maximum possible value of score they can get?
The first line contains a single integer n (1 ≤ n ≤ 3·105). The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 106) — the initial group that is given to Toastman.
Print a single integer — the largest possible score.
3
3 1 5
26
1
10
10
题解意思:
这是一道霍夫曼编码的反问题,把所有边权取反就是霍夫曼树问题,详细证明请看算法导论,大概证明一下:
可以把每次的拿来拆分的每一段的都作为树上的节点,长度为1的值必然是叶节点,会在统计一次后被抛出,这时父节点权值则是子节点权值之和,而且必然是一颗二叉树,这与题目是符合的,也就是说深度越大的叶节点加和的次数越多,那么把最大的那两个节点先放在树里,那么它们的父节点就拥有两个节点之和的性质,那么再添加次大的,如此构建就形成了整棵最优树,(算法导论可以严格证明这是棵最优树,通过反证法),于是除了最大的两个点加了n次,其余的点分别加了n-1,n-2,....2次
#include <cstdio>#include <algorithm>using namespace std;const int maxn=300005;int n;long long a[maxn];int main(){ scanf("%d",&n); long long ans=0,sum=0; for(int i=0;i<n;i++){scanf("%I64d",a+i);sum+=a[i];} sort(a,a+n); ans=sum; for(int i=1;i<n;i++){ ans+=sum; sum-=a[i-1]; } printf("%I64d\n",ans); return 0;}
D:
Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices are colored white.
Consider a set consisting of k (0 ≤ k < n) edges of Appleman‘s tree. If Appleman deletes these edges from the tree, then it will split into(k + 1) parts. Note, that each part will be a tree with colored vertices.
Now Appleman wonders, what is the number of sets splitting the tree in such a way that each resulting part will have exactly one black vertex? Find this number modulo 1000000007 (109 + 7).
The first line contains an integer n (2 ≤ n ≤ 105) — the number of tree vertices.
The second line contains the description of the tree: n - 1 integers p0, p1, ..., pn - 2 (0 ≤ pi ≤ i). Where pi means that there is an edge connecting vertex (i + 1) of the tree and vertex pi. Consider tree vertices are numbered from 0 to n - 1.
The third line contains the description of the colors of the vertices: n integers x0, x1, ..., xn - 1 (xi is either 0 or 1). If xi is equal to 1, vertex i is colored black. Otherwise, vertex i is colored white.
Output a single integer — the number of ways to split the tree modulo 1000000007 (109 + 7).
3
0 0
0 1 1
2
6
0 1 1 0 4
1 1 0 0 1 0
1
10
0 1 2 1 4 4 4 0 8
0 0 0 1 0 1 1 0 0 1
27
这是一道树形dp,我一开始想到奇怪的地方去了,什么连通域之类的
对每个点,dp记录使其的所有子树成为单黑或纯白的方式,最后再加上自身的黑/白属性
具体来说
初始化:子树单黑=0,子树纯白=1
单黑=现有单黑*子树纯白+子树单黑*现有纯白
纯白=现有纯白*子树纯白
然后加入自身的属性
如果自身为黑,那么单黑=子树纯白(现有黑:切掉所有子节点成为0)
如果自身为白,那么纯白*=子树纯白(切掉本身使得孤立的方式更多)
#include<cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int maxn=100005;const long long mod=1000000007 ;long long dp[maxn][2];int color[maxn];vector<int> G[maxn];bool vis[maxn];void dfs(int s){ dp[s][0]=1; dp[s][1]=0; vis[s]=true; for(int i=0;i<G[s].size();i++){ int t=G[s][i]; if(vis[t])continue; dfs(t); dp[s][1]=(dp[s][0]*dp[t][1]+dp[s][1]*dp[t][0])%mod; dp[s][0]=dp[s][0]*dp[t][0]%mod; } if(color[s]==1){ dp[s][1]=dp[s][0]; } else dp[s][0]+=dp[s][1]; dp[s][1]%=mod; dp[s][0]%=mod;}int main(){ int n; scanf("%d",&n); for(int i=1;i<n;i++){ int temp; scanf("%d",&temp); G[temp].push_back(i); } for(int i=0;i<n;i++)scanf("%d",color+i); dfs(0); printf("%I64d\n",dp[0][1]); return 0;}
E:
Appleman has a very big sheet of paper. This sheet has a form of rectangle with dimensions 1 × n. Your task is help Appleman with folding of such a sheet. Actually, you need to perform q queries. Each query will have one of the following types:
- Fold the sheet of paper at position pi. After this query the leftmost part of the paper with dimensions 1 × pi must be above the rightmost part of the paper with dimensions 1 × ([current width of sheet] - pi).
- Count what is the total width of the paper pieces, if we will make two described later cuts and consider only the pieces between the cuts. We will make one cut at distance li from the left border of the current sheet of paper and the other at distance ri from the left border of the current sheet of paper.
Please look at the explanation of the first test example for better understanding of the problem.
The first line contains two integers: n and q (1 ≤ n ≤ 105; 1 ≤ q ≤ 105) — the width of the paper and the number of queries.
Each of the following q lines contains one of the described queries in the following format:
- "1 pi" (1 ≤ pi < [current width of sheet]) — the first type query.
- "2 li ri" (0 ≤ li < ri ≤ [current width of sheet]) — the second type query.
For each query of the second type, output the answer.
7 4
1 3
1 2
2 0 1
2 1 2
4
3
10 9
2 2 9
1 1
2 0 1
1 8
2 0 8
1 2
2 1 3
1 4
2 2 4
7
2
10
4
5
翻折,当长度>len/2的时候那么就反向翻折,这时候相当于反向了一次,需要反着来统计
看上去思路很清晰但是很麻烦
#include<cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;const int maxn=100005;const int maxnode=400005;long long w[maxnode];int cur,s,e,len,n,q;int num(int i){//返回正确的标号,传入的是从开始的端点所需经过距离 if(cur==0){return s+i;} return e-i;}void update(int k,int d){//更新线段树 int tk=k; k+=n-1; w[k]+=d; while(k>0){ k=(k-1)/2; w[k]+=d; }}void inv(int l){//翻转 int tl; if(l*2>len){tl=len-l;cur^=1;}//翻转统计的同时就要反向更新了 else tl=l; for(int i=0;i<tl;i++){ int td=num(tl*2-1-i); int td2=num(i); update(td,w[td2+n-1]); update(td2,-w[td2+n-1]); } if(cur)e-=tl;else s+=tl; len=e-s+1;}long long query(int a,int b,int k,int l,int r){ if(r<=a||l>=b||l>=r)return 0; if(a<=l&&r<=b){ return w[k]; } else { long long v1=query(a,b,k*2+1,l,(l+r)/2); long long v2=query(a,b,k*2+2,(l+r)/2,r); return v1+v2; }}int main(){ scanf("%d%d",&n,&q);int tn=n,ttn=n;n=1; while(tn>0){n<<=1;tn>>=1;} for(int i=0;i<ttn;i++)update(i,1); s=0;e=ttn-1;len=ttn; while(q--){ int op; scanf("%d",&op); if(op==1){ int l; scanf("%d",&l); inv(l); } else{ int l,r; scanf("%d%d",&l,&r); if(cur){ l=num(l-1);//这里卡我半天因为题目给的是从s开始的序号所以从e开始就要+1,传进的参数要-1 r=num(r-1); } else { l=num(l); r=num(r); } if(l>r)swap(l,r); long long ans=query(l,r,0,0,n); printf("%I64d\n",ans); } }}
cf#263 div2 解题报告