【CF刷题】14-05-12

  Round 236 div.1

    A:只需要每个点连接所有比他大的点,知道边用完为止。  


//By BLADEVIL
#include <cmath>
#include <cstdio>
#define maxn 25;

using namespace std;

int main() {
int task; scanf("%d",&task);
while (task--) {
int n,p; scanf("%d%d",&n,&p);
int rest(2*n+p);
for (int i=1;(i<=n)&&rest;i++)
for (int j=i+1;(j<=n)&&rest;j++) printf("%d %d\n",i,j),rest--;
}
return 0;
}


View
Code

    B:求出g[i]=gcd(a[1],a[2]....a[i]),那么只需要从后向前贪心的考虑每个g[i]能不能被除掉就好了。


//By BLADEVIL
#include <cstdio>
#include <algorithm>
#define maxn 5010

using namespace std;

int n,m;
int a[maxn],b[maxn],g[maxn];

int calc(int x) {
int ans(0);
for (int i=1;i<=m;i++) while (!(x%b[i])) ans--,x/=b[i];
for (int i=2;i*i<=x;i++) while (!(x%i)) ans++,x/=i;
if (x>1) ans++;
return ans;
}

int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]),g[i]=__gcd(g[i-1],a[i]);
for (int i=1;i<=m;i++) scanf("%d",&b[i]);
int cur(1);
for (int i=n;i;i--) {
a[i]/=cur; g[i]/=cur;
if (calc(g[i])<0) cur*=g[i],a[i]/=g[i];
}
//for (int i=1;i<=n;i++) printf("%d ",a[i]); printf("\n");
int ans(0);
for (int i=1;i<=n;i++) ans+=calc(a[i]);
printf("%d\n",ans);
return 0;
}

  Round 238 div.1

    A:我们发现其实最后的答案只与a[i][i]有关,那么我们只记录a[i]=a[i][i],根据操作模拟就可以了。


//By BLADEVIL
#include <cstdio>
#define maxn 1010

using namespace std;

int n;
int mat[maxn][maxn],a[maxn];

int main() {
//freopen("data.txt","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) scanf("%d",&mat[i][j]);
for (int i=1;i<=n;i++) a[i]=mat[i][i];
int ans(0);
for (int i=1;i<=n;i++) ans=(ans+a[i])%2;
int task; scanf("%d",&task);
while (task--) {
int x,y; scanf("%d",&x);
if (x==3) printf("%d",ans); else {
scanf("%d",&x); ans^=1;
}
}
printf("\n");
return 0;
}

    B:我们可以将每个给定的a[i]-1,查询s-a[i]+1位置是否被占用,被占用我们cnt++,表示和为s-1的数对加一,否则直接输出s-a[i]+1,然后再找出cnt个和为s-1的数对输出。


//By BLADEVIL
#include <cstdio>
#define maxn 1000010
#define s 1000000

using namespace std;

int n,tot;
int flag[maxn];

int main() {
scanf("%d",&n);
for (int i=1;i<=n;i++) {
int x; scanf("%d",&x);
flag[x]=1; if (flag[s+1-x]) tot++;
}
printf("%d\n",n);
for (int i=1;i<=s;i++) {
if (tot&&!flag[i]&&!flag[s-i+1]) {
tot--;
flag[i]=flag[s-i+1]=1;
printf("%d %d ",i,s-i+1);
}
if (flag[i]&&!flag[s-i+1]) printf("%d ",s-i+1);
}
printf("\n");
return 0;
}

    C:深搜,同时每个点记录这个点剩下的一条没有被选定的边,枚举这个点的所有儿子,如果儿子的没有被选定的边不为0我们就画连接儿子的边和儿子剩下的边,否则判断这个点是否有剩下的边,有的话输出连接儿子的边和剩下的边,最后返回剩下的边。

 


//By BLADEVIL
#include <cstdio>
#define maxn 100010
#define maxm 200010

using namespace std;

int n,m,l;
int pre[maxm],other[maxm],last[maxn];
int flag[maxn];

void connect(int x,int y) {
pre[++l]=last[x];
last[x]=l;
other[l]=y;
}

int dfs(int x,int fa) {
flag[x]=1; int cur(0);
for (int p=last[x];p;p=pre[p]) {
if (other[p]==fa) continue;
if (flag[other[p]]==2) continue;
int edge;
if (!flag[other[p]]) edge=dfs(other[p],x); else edge=0;
//printf("|%d %d\n",x,edge);
if (edge) printf("%d %d %d\n",x,other[p],edge); else
if (cur) printf("%d %d %d\n",cur,x,other[p]),cur=0; else cur=other[p];
}
flag[x]=2;
//printf("%d %d\n",x,cur);
return cur;
}

int main() {
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
connect(x,y); connect(y,x);
}
if (m&1) printf("No solution\n\n"); else dfs(1,-1);
return 0;
}

    D:我们将每条线段能看到的最右面的线段设为这个线段的父亲,那么一个询问的答案就是这两个点的lca,对于父亲我们可以维护一个下凸壳来计算。


//By BLADEVIL
#include <cstdio>
#include <iostream>
#include <algorithm>
#define maxn 200010
#define LL long long

using namespace std;

struct rec {
LL x,y;
}a[maxn];

int n,t,l;
int q[maxn],jump[maxn][20];
int pre[maxn],other[maxn],last[maxn],dep[maxn];

void connect(int x,int y) {
pre[++l]=last[x];
last[x]=l;
other[l]=y;
}

int lca(int x,int y) {
if (dep[x]>dep[y]) swap(x,y);
int det(dep[y]-dep[x]);
for (int j=0;j<=18;j++) if (det&(1<<j)) y=jump[y][j];
//printf("%d %d\n",x,y);
if (x==y) return x;
for (int j=18;j>=0;j--)
if (jump[x][j]!=jump[y][j]) x=jump[x][j],y=jump[y][j];
return jump[x][0];
}

void dfs(int x) {
for (int p=last[x];p;p=pre[p]) {
dep[other[p]]=dep[x]+1;
dfs(other[p]);
}
}

int main() {
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;
for (int i=n;i;i--) {
//for (int j=1;j<=t;j++) printf("%d ",q[j]); printf("\n");
while (t>1&&(a[q[t]].y-a[q[t-1]].y)*(a[i].x-a[q[t-1]].x)>(a[q[t]].x-a[q[t-1]].x)*(a[i].y-a[q[t-1]].y)) t--;
jump[i][0]=q[t];
q[++t]=i;
}
//for (int i=1;i<=n;i++) printf("%d ",jump[i][0]);
for (int i=1;i<=n;i++) connect(jump[i][0],i);
dfs(0);
//for (int i=1;i<=n;i++) printf("%d ",dep[i]); printf("\n");
for (int j=1;j<=18;j++)
for (int i=1;i<=n;i++) jump[i][j]=jump[jump[i][j-1]][j-1];
int task; cin>>task;
while (task--) {
int x,y; cin>>x>>y;
cout<<lca(x,y)<<‘ ‘;
}
cout<<endl;
return 0;
}

  Round 240 div.1

    A:假设n为偶数,奇数时最后一位随意,那么我们最后两个数为k-(n+2)/2和2*(k-(n+2)/2),前n-2个数为不和最后两位相同的连续的数就可以了。


//By BLADEVIL
#include <cstdio>
#define maxn 100010

using namespace std;

int n,k;
int a[maxn];

int main() {
scanf("%d%d",&n,&k);
if ((n==1)&&(k)) {
printf("-1\n");
return 0;
}
if (n-(n&1)>2*k) {
printf("-1\n");
return 0;
}
int cur((n-2-(n&1))/2);
k-=cur;
a[n]=1000001+k;
for (int i=1,j=1;i<=n-2-(n&1);i+=2) {
if (j==k) j+=100;
if (j+1==k) j+=100;
if (j==(k<<1)) j+=100;
if (j+1==(k<<1)) j+=100;
a[i]=j++; a[i+1]=j++;
}
a[n-(n&1)]=k,a[n-1-(n&1)]=k<<1;
for (int i=1;i<=n;i++) printf(i==n?"%d\n":"%d ",a[i]);
return 0;
}

    B:设w[i][j]为第i位为j的方案数,然后转移就可以了。


//By BLADEVIL
#include <cmath>
#include <cstdio>
#define maxn 2010
#define d39 1000000007

using namespace std;

int n,k;
int w[maxn][maxn];

int main() {
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) w[1][i]=1;
for (int i=2;i<=k;i++)
for (int j=1;j<=n;j++)
for (int g=1;g<=sqrt(j);g++) if (!(j%g)) {
w[i][j]=(w[i][j]+w[i-1][g])%d39;
if (g*g!=j) w[i][j]=(w[i][j]+w[i-1][j/g])%d39;
}
int ans(0);
for (int i=1;i<=n;i++) ans=(ans+w[k][i])%d39;
printf("%d\n",ans);
return 0;
}

    C:我们可以将一次翻转看成将左右儿子翻转然后交换左右儿子,我们可以发现每个块内的翻转对块与块之间的答案没有影响,那么我们只需要按照归并的过程求出长度为2^j的块与块合并的时候产生的答案,和交换块产生的答案,那么每次翻转我们就可以看做将j之前的所有当前状态取反,计算代价即可。


//By BLADEVIL
#include <cstdio>
#include <cstring>
#include <iostream>
#define maxn (1<<20)+100
#define LL long long

using namespace std;

LL n,len;
LL a[maxn],b[maxn];
LL w[30][2],flag[30];

void work(LL p,LL cur) {
if (p>n) return ;
for (LL i=1;i<=len;i+=cur) {
LL k1(i),k2(i+(cur>>1)),det(0);
while ((k1<i+(cur>>1))||(k2<i+cur)) {
if ((k1==i+(cur>>1))||((a[k2]<a[k1])&&(k2<i+cur))) {
w[p][0]+=i+(cur>>1)-k1;
b[i+det]=a[k2];
k2++;
} else {
b[i+det]=a[k1];
k1++;
}
det++;
}
k1=i+(cur>>1); k2=i;
while ((k1<i+cur)||(k2<i+(cur>>1))) {
if ((k1==i+cur)||((a[k2]<a[k1])&&(k2<i+(cur>>1)))) {
w[p][1]+=i+cur-k1;
k2++;
} else k1++;
}
}
memcpy(a,b,sizeof b);
work(p+1,cur<<1);
}

int main() {
cin>>n; len=1;
for (LL i=1;i<=n;i++) len*=2;
for (LL i=1;i<=len;i++) cin>>a[i];
work(1,2);
LL ans(0);
for (LL i=1;i<=n;i++) ans+=w[i][0];
//for (LL i=1;i<=n;i++) printf("%d ",w[i][0]); printf("\n");
//for (LL i=1;i<=n;i++) printf("%d ",w[i][1]); printf("\n");
for (LL i=1;i<=n;i++) flag[i]=1;
//printf("%d\n",ans);
LL task; cin>>task;
while (task--) {
LL x; cin>>x;
for (LL i=1;i<=x;i++) ans+=w[i][flag[i]]-w[i][flag[i]^1];
for (LL i=1;i<=x;i++) flag[i]^=1;
cout<<ans<<endl;
}
return 0;
}

    Round 245 div.1

    A:tree-dp,设w[i][0..1]表示这个节点的状态和最后的相同(1),不相同(0),且每两层的儿子节点都符合这个状态的最小代价,然后转移就可以了,其实这道题相当于两棵互不影响的树,分别做tree-dp。


//By BLADEVIL
#include <cstdio>
#define maxn 100010
#define maxm 200020

using namespace std;

int n,l;
int a[maxn],b[maxn];
int other[maxm],last[maxn],pre[maxm];
int que[maxn],dep[maxn];
int w[maxn][2];

void connect(int x,int y) {
pre[++l]=last[x];
last[x]=l;
other[l]=y;
}

void dfs(int x,int cur) {
if (a[x]^b[x]^(!cur)) printf("%d\n",x),cur^=1;
for (int p=last[x];p;p=pre[p]) if (dep[other[p]]>dep[x])
for (int q=last[other[p]];q;q=pre[q]) if (dep[other[q]]>dep[other[p]])
dfs(other[q],cur);
}

int main() {
scanf("%d",&n);
for (int i=1;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
connect(x,y); connect(y,x);
}
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
int h(0),t(1);
que[1]=1; dep[1]=1;
while (h<t) {
int cur=que[++h];
for (int p=last[cur];p;p=pre[p]) {
if (dep[other[p]]) continue;
que[++t]=other[p]; dep[other[p]]=dep[cur]+1;
}
}
for (int i=n;i;i--) {
int x=que[i];
for (int p=last[x];p;p=pre[p]) {
if (dep[other[p]]<dep[x]) continue;
//w[x][0]+=w[other[p]][1]; w[x][1]+=w[other[p]][1];
for (int q=last[other[p]];q;q=pre[q]) {
if (dep[other[q]]<dep[other[p]]) continue;
if (a[x]^b[x]) w[x][0]+=w[other[q]][0]; else w[x][0]+=w[other[q]][1];
if (a[x]^b[x]) w[x][1]+=w[other[q]][0]; else w[x][1]+=w[other[q]][1];
}
}
if (a[x]^b[x]) w[x][1]++; else w[x][0]++;
}
//for (int i=1;i<=n;i++) printf("%d %d\n",w[i][0],w[i][1]);
int ans(w[1][1]);
for (int p=last[1];p;p=pre[p]) ans+=w[other[p]][1];
printf("%d\n",ans);
dfs(1,1);
for (int p=last[1];p;p=pre[p]) dfs(other[p],1);
return 0;
}

    B:记录w[i][j][1..4]表示四个方向到i,j点的最大值,然后枚举相遇的节点就可以了。


//By BLADEVIL
#include <cstdio>
#include <iostream>
#include <algorithm>
#define maxn 1010
#define LL long long

using namespace std;

LL n,m;
LL a[maxn][maxn];
LL w[5][maxn][maxn];

void prepare() {
for (LL i=1;i<=n;i++)
for (LL j=1;j<=m;j++) w[1][i][j]=max(w[1][i][j-1],w[1][i-1][j])+a[i][j];
for (LL i=1;i<=n;i++)
for (LL j=m;j;j--) w[2][i][j]=max(w[2][i][j+1],w[2][i-1][j])+a[i][j];
for (LL i=n;i;i--)
for (LL j=1;j<=m;j++) w[3][i][j]=max(w[3][i+1][j],w[3][i][j-1])+a[i][j];
for (LL i=n;i;i--)
for (LL j=m;j;j--) w[4][i][j]=max(w[4][i+1][j],w[4][i][j+1])+a[i][j];
}

int main() {
cin>>n>>m;
for (LL i=1;i<=n;i++)
for (LL j=1;j<=m;j++) cin>>a[i][j];
prepare();
LL ans(0);
for (LL i=2;i<n;i++)
for (LL j=2;j<m;j++)
ans=max(ans,w[1][i-1][j]+w[4][i+1][j]+w[2][i][j+1]+w[3][i][j-1]),
ans=max(ans,w[1][i][j-1]+w[4][i][j+1]+w[2][i-1][j]+w[3][i+1][j]);
cout<<ans<<endl;
return 0;
}


View
Code

    C:深搜就可以了,有一种贪心不正确但是数据弱可以过去。


#include <cstdio>
#include <iostream>
#include <algorithm>
#define maxn 30

using namespace std;

int n;
int w[maxn],p[maxn];

int dfs(int x,int used) {
//printf("%d %d\n",x,used);
if (x>n) return *max_element(p+1,p+1+n)==0;
for (int i=1;i<=x;i++)
if ((p[i]>w[x]||p[i]==w[x]&&p[i]!=w[i]-1)&&((used&(1<<p[i])))==0) {
p[i]-=w[x];
if (dfs(x+1,x+1<=n&&w[x]==w[x+1]?used:0)) return 1;
p[i]+=w[x];
used|=1<<p[i];
}
return 0;
}

int main() {
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&w[i]);
sort(w+1,w+1+n,greater<int>());
for (int i=1;i<=n;i++) p[i]=w[i]-1;
printf(dfs(2,0)?"YES\n":"NO\n");
}

【CF刷题】14-05-12

时间: 2024-07-28 22:35:59

【CF刷题】14-05-12的相关文章

[14.05.12]今后讨论班的走向

今后讨论班的一些走向 谨记之...... 上周末决定,今后讨论班将针对CVPR 2014和SIAM Conference on IMAGING SCIENCE(2014) 进行进一步的挖掘.上级给我们刚刚布置了SIAM会议的日程.内容安排,看完之后,顿觉亚历山大啊......会是好会,会址更是博主心仪之地.虽不能至,心向往之...... http://www.math.hkbu.edu.hk/SIAM-IS14/ 会议介绍里面有个词用的很好:from nano-scale to the astr

HDU 4788 (14.05.12)

Hard Disk Drive Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 647    Accepted Submission(s): 350 Problem Description Yesterday your dear cousin Coach Pang gave you a new 100MB hard disk drive

刷题 11/05

从昨天开始刷题,但是昨天比较懒,没有总结一下.今天开始总结一下刷题什么的遇到的bug和之前不注意的事情. 顺时针旋转矩阵 有一个NxN整数矩阵,请编写一个算法,将矩阵顺时针旋转90度. 给定一个NxN的矩阵,和矩阵的阶数N,请返回旋转后的NxN矩阵,保证N小于等于300. 很简单的矩阵变换,我是通过两次矩阵变换得到的,首先对角线交换,然后左右翻转就可以了. class Rotate: def rotateMatrix(self, mat, n): c = [[0 for i in range(0

刷题14 调整数组顺序使奇数位于偶数前面

描述:  输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 假如只需要将奇数位于数组前半部分,偶数位于数组的后半部分, 直接用快速排序解决就好. 但是这里还需要保证奇数间,偶数之间的相对位置不变, 在这里就使用插入排序好了. 1 class Solution { 2 public: 3 void reOrderArray(vector<int> &array) {

leetcode刷题14

今天刷的题是LeetCode236题,是给定一个二叉树,以及二叉树中的两个节点,然后找出两个节点的最近公共祖先 上一道题我自己的解法在这道题依旧适用,即找出两节点到根节点的路径,然后遍历. 我自己的解法,当时为了找到这条路径费了很多劲儿.这道题参考了哈LeetCode的官方解答思路,说可以用父指针的方式来解决.因此这里用了一个map集合 key保存的是当前节点,value保存的是父节点 首先是一个递归遍历,找出除了根节点外的所有节点的父节点 然后是查找.具体地代码如下: import Leetc

【leetcode刷题笔记】Letter Combinations of a Phone Number

Given a digit string, return all possible letter combinations that the number could represent. A mapping of digit to letters (just like on the telephone buttons) is given below. Input:Digit string "23" Output: ["ad", "ae", &q

【leetcode刷题笔记】Sum Root to Leaf Numbers

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. An example is the root-to-leaf path 1->2->3 which represents the number 123. Find the total sum of all root-to-leaf numbers. For example, 1 / 2 3 T

【leetcode刷题笔记】Longest Consecutive Sequence

Given an unsorted array of integers, find the length of the longest consecutive elements sequence. For example,Given [100, 4, 200, 1, 3, 2],The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. Your algorithm should run in

【leetcode刷题笔记】Remove Duplicates from Sorted Array II

Follow up for "Remove Duplicates":What if duplicates are allowed at most twice? For example,Given sorted array A = [1,1,1,2,2,3], Your function should return length = 5, and A is now [1,1,2,2,3]. 题解: 设置两个变量:右边kepler和前向游标forward.如果当前kepeler所指的元素和