Codechef_JULY14
感觉这套比赛题目比较容易,没有以前做过的某次codechef那么凶残。题目还是很有意思的,最好的是有中文翻译。
CSUB:签到题,直接从左往右扫一遍即可,维护前面出现过多少个1.
#include <cstdio>
#include <cstring>
#define maxn 100100
using namespace std; char s[maxn];
long long ans;
int cur,T,n; int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d%s",&n,s);
ans=cur=;
for (int i=; s[i]; i++)
if (s[i]=='') ans+=++cur;
printf("%lld\n",ans);
}
return ;
}
RETPO:简单找规律。注意一开始的朝向,同时根据对称性,所有的点都可以对称到第一象限来。要走弯路的话,第一个单位距离消耗3步,第二个单位距离消耗1步,第三个消耗3步,第四个1步,依次类推即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; long long x,y,n,ans;
int T; int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%lld%lld",&x,&y);
if (x<) x=-x;
if (y<) y=-y;
n=y-x;
if (n>= && n<=) ans=x+y;
else
{
if (n<) n=-n;
if (y>x) ans=*min(x,y)+(n/)*+(n&)*;
else ans=*min(x,y)+(n/)*+(n&)*;
}
printf("%lld\n",ans);
}
return ;
}
FROGV:氺题。对于每只青蛙,f[i]保存它向右最远可以传递到那一只青蛙,假设当前我们计算第i只青蛙,对于j>i,且i可以传递信息给j,那么f[i]=max(f[j])。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 100100
using namespace std; int g[maxn],f[maxn];
int n,m,k,x,y; struct node{
int x,id;
}a[maxn]; bool cmp(node n1,node n2)
{
return n1.x<n2.x;
} int main()
{
scanf("%d%d%d",&n,&k,&m);
for (int i=; i<=n; i++) scanf("%d",&a[i].x),a[i].id=i;
sort(a+,a++n,cmp); for (int i=; i<=n; i++) g[a[i].id]=i; f[n]=n;
for (int i=n-; i>; i--)
if (a[i+].x-a[i].x<=k) f[i]=f[i+];
else f[i]=i;
while (m--)
{
scanf("%d%d",&x,&y);
x=g[x],y=g[y];
if (x>y) swap(x,y);
if (y<=f[x]) puts("Yes");
else puts("No");
}
return ;
}
SGARDEN:数学题。对于一种置换,它里面一定构成了若干个环。所有人都回到原地的步数就是所有环长度的lcm值。由于这个lcm值很大,必须对于每个环长度进行因数分解,保存每个质数出现的次数就可。最后取模计算。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#define maxn 100100
typedef long long ll;
using namespace std; const int M=;
int a[maxn],T,n,cur,N;
bool b[maxn];
ll ans;
map<int,int> ss; void dfs(int x)
{
if (b[x]) return;
cur++,b[x]=true;
dfs(a[x]);
} void deal(int x)
{
for (int i=; i*i<=x; i++)
{
if (x%i) continue;
N=;
while (x%i==) x/=i,N++;
ss[i]=max(ss[i],N);
}
if (x>) ss[x]=max(ss[x],);
} int main()
{
scanf("%d",&T);
while (T--)
{
ss.clear();
ans=;
scanf("%d",&n);
for (int i=; i<=n; i++) scanf("%d",&a[i]),b[i]=false;
for (int i=; i<=n; i++)
if (!b[i])
{
cur=;
dfs(i);
deal(cur);
}
for (int i=; i<=n; i++)
while (ss[i]--) ans=(ans*i)%M;
printf("%lld\n",ans);
}
return ;
}
DISHOWN:一看这个题目就是一个典型的并查集了。每次查找盘子的主人,然后两个主人之间的比较无非就是改变一下指针而已了,路径压缩,所有的操作都是O(1)的。
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 10010
using namespace std; int a[maxn],f[maxn];
int n,q,T; int father(int x) { return f[x]==x?f[x]:f[x]=father(f[x]); } int main()
{
int ope,x,y;
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
for (int i=; i<=n; i++) scanf("%d",&a[i]),f[i]=i;
scanf("%d",&q);
while (q--)
{
scanf("%d",&ope);
if (ope==)
{
scanf("%d%d",&x,&y);
x=father(x),y=father(y);
if (a[x]==a[y])
{
if (x==y) puts("Invalid query!");
continue;
}
if (a[x]>a[y]) f[y]=x;
else f[x]=y;
}
else
{
scanf("%d",&x);
printf("%d\n",father(x));
}
}
}
return ;
}
LEPAINT:这个题目我一开始以为我会T。没想到写了一发最最暴力的居然都A掉了。不过我觉得这个应该是被卡掉的,只是数据不够强吧。优化可以是这样的,对于物品,直接预处理它染色多少次后,为某种颜色的概率。同时,后面的区间染色就用扫描区间的方法,直接得出,直接求和即可。对于题目所说的取子集的问题,就相当于在这个范围里面每一个物品都有0.5的概率被染色。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std; double f[][],tmp[],ans;
int L,R,n,m,c,T; int main()
{
scanf("%d",&T);
while (T--)//
{
scanf("%d%d%d",&n,&c,&m);
for (int i=; i<=n; i++)
{
for (int j=; j<c; j++) f[i][j]=;
f[i][]=;
}
while (m--)//
{
scanf("%d%d",&L,&R);
for (int i=L; i<=R; i++)//
{
for (int j=; j<c; j++) f[i][j]/=,tmp[j]=f[i][j];
for (int j=; j<c; j++)//
for (int k=; k<c; k++)//
f[i][j*k%c]+=tmp[j]/c;
}
} ans=;
for (int i=; i<=n; i++)
for (int j=; j<c; j++) ans+=f[i][j]*j;
printf("%.9f\n",ans);
} return ;
}
GNUM:很好的一个题目。一开始我就看准了这个题目,花时间最多的一个题目。读完题目后直接想到的就是二分图取匹配。显然是T。可以建模来解。以a[i]<b[j]且满足gcd条件的点位左边点,连接源点,以a[i]>b[j]且满足gcd条件的点为右点,连接汇点。中间是gcd出现过的质数,分别连接相应的左右点,所有的边流量都是1,跑最大流即可。这个做法肯定是没有错的。但是还是有一些问题存在。点太多了。咋解决?缩点,分别把左右边的点中含有相同的质因子种类的点缩成一个点,边容量累加。再跑最大流,缩点后,点数的级别也就1000吧,可以ac。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <map>
#define maxn 2002000
#define maxpri 100100
using namespace std; int pri[maxpri],pnum=,antipri[maxpri];
int z[][],Z[],a[],aa[];
int to[maxn],c[maxn],next[maxn],first[maxn],edge,node;
int tag[maxn],d[maxn],Q[maxn],bot,top,TAG=;
int f[][],Tf;
bool can[maxn];
int T,n,tmp,s,t,ans,cas;
map<int,int> ss,pos,Ttime;//质�对������ int gcd(int A,int B) { return B==?A:gcd(B,A%B); } void getprim()
{
for (int i=; i<maxpri; i++)
{
if (antipri[i]==-) continue;
pri[++pnum]=i; antipri[i]=pnum;
for (int j=i+i; j<maxpri; j+=i) antipri[j]=-;
}
} int addnode()
{
node++;
first[node]=-;
return node;
} void _init()
{
ss.clear(),pos.clear(),Ttime.clear();
edge=-,node=,Tf=;
s=addnode(),t=addnode();
ans=;
} void addedge(int U,int V,int W)
{
edge++;
to[edge]=V,c[edge]=W,next[edge]=first[U],first[U]=edge;
edge++;
to[edge]=U,c[edge]=,next[edge]=first[V],first[V]=edge;
} void deal(int x)
{
Z[x]=,tmp=a[x],aa[x]=tmp;
for (int i=; pri[i]<=tmp/pri[i]; i++)
if (tmp%pri[i]==)
{
z[x][++Z[x]]=pri[i];
while (tmp%pri[i]==) tmp/=pri[i];
}
if (tmp>) z[x][++Z[x]]=tmp; for (int i=; i<=Z[x]; i++)
while (((aa[x]/z[x][i])%z[x][i])==) aa[x]/=z[x][i];
} void buildedge()
{
for (int x=; x<=n; x++)
for (int y=n+; y<=n+n; y++)
if (a[x]<a[y] && gcd(aa[x],aa[y])>)
{
int cur=gcd(aa[x],aa[y]);
if (pos[cur]) { Ttime[cur]=Ttime[cur]+; continue; }
pos[cur]=++Tf,f[Tf][]=,Ttime[cur]=;
for (int i=; i<=Z[x]; i++)
if (aa[y]%z[x][i]==) f[Tf][++f[Tf][]]=z[x][i];
f[Tf][f[Tf][]+]=cur;
} for (int i=; i<=Tf; i++)
{
int cur=f[i][f[i][]+],tc=Ttime[cur],Nd=addnode();//Nd为��gcd代表���
addedge(s,Nd,tc);
for (int j=; j<=f[i][]; j++)
{
if (ss[f[i][j]]==) ss[f[i][j]]=addnode();
addedge(Nd,ss[f[i][j]],tc);
}
} pos.clear(),Tf=; for (int x=; x<=n; x++)
for (int y=n+; y<=n+n; y++)
if (a[x]>a[y] && gcd(aa[x],aa[y])>)
{
int cur=gcd(aa[x],aa[y]);
if (pos[cur]) { Ttime[cur]=Ttime[cur]+; continue; }
pos[cur]=++Tf,f[Tf][]=,Ttime[cur]=;
for (int i=; i<=Z[x]; i++)
if (aa[y]%z[x][i]==) f[Tf][++f[Tf][]]=z[x][i];
f[Tf][f[Tf][]+]=cur;
}
for (int i=; i<=Tf; i++)
{
int cur=f[i][f[i][]+],tc=Ttime[cur],Nd=addnode();//Nd为��gcd代表���
addedge(Nd,t,tc);
for (int j=; j<=f[i][]; j++)
{
if (ss[f[i][j]]==) continue;
addedge(ss[f[i][j]],Nd,tc);
}
}
} bool bfs()
{
TAG++;
Q[bot=top=]=t,d[t]=,tag[t]=TAG,can[t]=false;
while (bot<=top)
{
int cur=Q[bot++];
for (int i=first[cur]; i!=-; i=next[i])
if (c[i^]> && tag[to[i]]!=TAG)
{
tag[to[i]]=TAG,Q[++top]=to[i],d[to[i]]=d[cur]+,can[to[i]]=false;
if (to[i]==s) return true;
}
}
return false;
} int dfs(int cur,int num)
{
if (cur==t) return num;
int tmp=num,k;
for (int i=first[cur]; i!=-; i=next[i])
if (c[i]> && d[to[i]]==d[cur]- && tag[to[i]]==TAG && can[to[i]]==false)
{
k=dfs(to[i],min(num,c[i]));
if (k) num-=k,c[i]-=k,c[i^]+=k;
//if (num==0) return tmp;
}
if (num) can[cur]=true;
return tmp-num;
} int main()
{
getprim();
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
for (int i=; i<=*n; i++) scanf("%d",&a[i]),deal(i);
_init();
buildedge();
while (bfs()) ans+=dfs(s,maxn);
printf("%d\n",ans);
}
return ;
}
SEAEQ:为什么这是整场比赛通过人数最少的题目?我觉得在平时比赛这种难度的题目也就算中等吧?此题让我想去去年杭州赛的那个题。深坑呐。解法是这样的,dp预处理长度为i的排列有不超过j个逆序数对的情况有多少种!这个可以dp好好想想就知道了,剩下的就是逆推枚举了,直接枚举区间长度,位置,对于两个排列其他的位置都是全排列即可。对于题目的那个要求就是在规定区间内,每个位置的相对大小相同即可,这个只需要保证对于预处理的种类数乘一次,对于取组合数和全排列数乘以两次即可。不难理解,自己想想就很清楚了。一开始取模打成了1000000009,都怪前几天打的那场acdream,坑死啦。
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 502
typedef long long ll;
using namespace std; const int M=;
int n,e,T,ans;
int sum[maxn][(maxn*maxn-maxn)/];//�度����对�
ll P[maxn],C[maxn][maxn]; int main()
{
P[]=,C[][]=;
for (int i=; i<maxn; i++) P[i]=(P[i-]*i)%M;
for (int i=; i<maxn; i++)
{
C[i][]=;
for (int j=; j<=i; j++) C[i][j]=(C[i-][j-]+C[i-][j])%M;
}
int last=,next;
sum[][]=;
for (int i=; i<maxn; i++)
{
next=last+i-;
sum[i][]=;
for (int j=; j<i; j++)
{
sum[i][j]=sum[i][j-]+sum[i-][j];
if (sum[i][j]>=M) sum[i][j]-=M;
}
for (int j=i; j<=last; j++)
{
sum[i][j]=sum[i][j-]+sum[i-][j]-sum[i-][j-i];
if (sum[i][j]>=M) sum[i][j]-=M;
if (sum[i][j]<) sum[i][j]+=M;
}
for (int j=last+; j<=next; j++)
{
sum[i][j]=sum[i][j-]+sum[i-][last]-sum[i-][j-i];
if (sum[i][j]>=M) sum[i][j]-=M;
if (sum[i][j]<) sum[i][j]+=M;
}
last=next;
}
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&e);
ans=;
for (int i=; i<=n; i++)
{
int cur=min((i*i-i)/,e);
cur=sum[i][cur];
ll tmp=(C[n][i]*P[n-i])%M;
tmp=((tmp*tmp)%M*cur)%M;
ans+=(tmp*(n+-i))%M;
if (ans>=M) ans-=M;
}
printf("%d\n",ans);
} return ;
}
Codechef_JULY14的更多相关文章
随机推荐
- JS字符串补全方法padStart()和padEnd()
背景: var t = new Date().getMonth() + 1; // t ===> 7,没有0,怎么展示成下面的样子? // 2018-07-23 解决上述问题的一个思路: // ...
- 解决table td里面长串数字或字母不换行的问题
在html中,经常要用到table标签,一般情况下,table下面的td元素里的东西都是汉字或者说是汉字.字母.数字的混合,在这种情况下,不设置table的宽度,也就是table宽度自适应的时候,浏览 ...
- SSD固态硬盘的GC与Trim
操作系统:其实并没有删除数据: 事实上,它只是在硬盘前的索引区里标记这块文件占用的区域为无效的, 所以等该区域被擦除后,下次数据将要再次写入的时候,可以写入这块被标记的区域. 这也就是为啥那 些所谓的 ...
- [Java] Design Pattern:Code Shape - manage your code shape
[Java] Design Pattern:Code Shape - manage your code shape Code Shape Design Pattern Here I will intr ...
- TCP/IP理解
目录 1.概述 2.TCP/IP寻址及其协议族 3.TCP/IP 邮件 1.概述 介绍:什么是TCP/IP? TCP/IP协议是对计算机必须遵守的规则的描述,遵守了规则才能通信. 应用: 浏览器与服务 ...
- 正则表达式30min
如何使用本教程 正则表达式到底是什么东西? 入门 测试正则表达式 元字符 字符转义 重复 字符类 分枝条件 反义 分组 后向引用 零宽断言 负向零宽断言 注释 贪婪与懒惰 处理选项 平衡组/递归匹配 ...
- nGrinder性能测试平台的安装部署
1.从GitHub下载war包: https://github.com/naver/ngrinder/releases 2.把ngrinder-controller-3.4.2.war重命名为ngri ...
- OpenCV颜色转换和皮肤检测
本笔记重点记录OpenCV中的颜色转换和利用色彩空间的特性进行皮肤检测 颜色转换 实现原理 之所以要引入色调/饱和度/亮度的色彩空间概念,是因为人们喜欢凭直觉分辨各种颜色,而它与这种方式吻合.实际上, ...
- 【UGUI】 (三)------- 背包系统(上)之简易单页背包系统及检索功能的实现
背包系统,无论是游戏还是应用,都是常常见到的功能,其作用及重要性不用我多说,玩过游戏的朋友都应该明白. 在Unity中实现一个简易的背包系统其实并不是太过复杂的事.本文要实现的是一个带检索功能的背包系 ...
- GitHub笔记(二)——远程仓库的操作
二 远程仓库 1 创建联系 第1步:创建SSH Key.在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一 ...