1112
董神出的题目 第一次成功卡上200pts...
A 物理
问题描述
物理课上,nodgd一拍脑袋,发明了一个最短路算法:给无向图的每个节点制作一个小球,
每条边制作一根绳子,绳子的长度就是边的权值;将最短路问题的起点对应的小球缓缓提
起,然后测量每个小球到起点小球的距离,就得到了起点到每个节点的最短路。nodgd发现
这个算法非常厉害——它的时间复杂度为O(1) 。
nodgd打算在课上给大家演示这个最短路算法,于是用数据生成器生成了一组数据,即一个
个节点 条边的无向图。nodgd发现,分别选取不同的最短路起点,有些绳子总是处于松
弛状态,有些绳子总是处于绷紧状态,剩下的绳子时而绷紧时而松弛,这样可以将绳子分成
三类。现在nodgd想知道,每种绳子属于哪一类?
输入格式
输入文件phys.in。
第一行两个整数 nm,表示无向图的节点数和边数。
接下来 m行,每行三个整数 abc,表示第 i条无向边连接 ab节点,权值为 c。保证没
有重边和自环。
输出格式
输出文件phys.out。
输出 m行,第 i行输出一个整数x , 分别表示第 x根绳子总是总是松弛、总是绷
紧、时而绷紧时而松弛。
输入输出样例1
见下发的文件phys-sample1.in和phys-sample1.ans。
董神还是这么毒瘤 专门卡dij
看到\(n<=500\) 邻接存图 floyd呗 dij主要处理点多边少的情况
然后讨论每个点的情况 如果这个点处于一条边的端点 就可以讨论是否为最短距离
如果不是端点讨论边是否存在于最短路中 否则就不行
code:
//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 510
#define ll long long
#define inf 100000000000
bool is[250010],son[250010];
struct node {
int st,en;
ll l;
} ed[250010];
ll mapp[maxnn][maxnn];
int n,m;
ll x,y,z;
#define GC getchar()
inline int R() {
char t;
int x=0;
int f=1;
t=GC;
while(!isdigit(t)) {
if(t=='-') f=-1;
t=GC;
}
while(isdigit(t)) {
x=x*10+t-48;
t=GC;
}
return x*f;
}
int main() {
freopen("phys.in","r",stdin);
freopen("phys.out","w",stdout);
n=R();
m=R();
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(i==j) continue;
mapp[i][j]=inf;
}
}
for(int i=1; i<=m; i++) {
ed[i].st=R();
ed[i].en=R();
ed[i].l=R();
mapp[ed[i].st][ed[i].en]=mapp[ed[i].en][ed[i].st]=ed[i].l;
}
for(int k=1; k<=n; k++) {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(mapp[i][j]>mapp[i][k]+mapp[k][j]) {
mapp[i][j]=mapp[i][k]+mapp[k][j];
}
}
}
}
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
if(ed[j].st==i) {
if(mapp[i][ed[j].en]==ed[j].l) {
is[j]=true;
continue;
}
continue;
}
if(ed[j].en==i) {
if(mapp[i][ed[j].st]==ed[j].l) {
is[j]=true;
continue;
}
continue;
}
if(mapp[i][ed[j].en]+ed[j].l==mapp[i][ed[j].st]) {
is[j]=true;
continue;
}
if(mapp[i][ed[j].st]+ed[j].l==mapp[i][ed[j].en]) {
is[j]=true;
continue;
}
son[j]=true;
}
}
for(int i=1; i<=m; i++) {
if((!is[i])&&son[i]) {
printf("1\n");
continue;
}
if(is[i]&&(!son[i])) {
printf("2\n");
continue;
}
if(is[i]&&(son[i])) {
printf("3\n");
continue;
}
}
}
B. 数学
(math.c/.cpp/.in/.out)
问题描述
扎实的数学功底是每个信息学竞赛选手必须具备的基本素养之一。
比如计算一个正整数 n有多少个正约数,通常的做法是先将 n分解质因数,将每个质因数的
幂次加一之后乘起来。
现在nodgd给你一个正整数序列 i,k,并进行很多次询问:序列前 i个数的乘积有
多少个正约数的所有质因数都不超过k 呢?特别的,1 没有质因数,所以无论怎么询问 总是
符合条件。
输入格式
输入文件math.in。
第一行两个整数 ,表示序列的长度和询问的次数。
第二行 个正整数 。
从第三行起的连续 行,每行两个正整数 ,表示一次询问。
输出格式
解:
树状数组维护前缀乘积 .... 话说lhd说过可以做区间gcd 我怎么就没想到 ... 因为我打了O(sqrt(n)) 还发现自己造的极限数据跑的贼快 (sqrt(n))分解我真是厉害
一定要把自己的思路记下来 不然就会忘记自己以前想过的思路...
或者建立权值线段树 直接记一下就行了
code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxnn =1e6;
const ll mod =998244353;
struct node {
ll l,r,v;
} tr[maxnn];
void build(int p,int x,int y) {
if(x==y) {
tr[p].l=x;
tr[p].r=y;
tr[p].v=1;
return ;
} else {
int mid=(x+y)>>1;
build(p<<1,x,mid);
build(p<<1|1,mid+1,y);
tr[p].l=x;
tr[p].r=y;
tr[p].v=1;
}
tr[p].v=(tr[p<<1].v*tr[p<<1|1].v)%mod;
}
ll get(int p,int x,int y) {
if(tr[p].l>=x&&tr[p].r<=y) {
return tr[p].v;
}
int mid=(tr[p].l+tr[p].r)>>1;
ll lll,rr;
lll=1;
rr=1;
if(x<=mid) lll=get(p<<1,x,y);
if(y>mid) rr=get(p<<1|1,x,y);
return (lll*rr)%mod;
}
void add(int p,int x,int d) {
if(tr[p].l==tr[p].r) {
tr[p].v++;
return ;
} else {
int mid=(tr[p].l+tr[p].r)>>1;
if(x<=mid)add(p<<1,x,d);
else if(x>mid) add(p<<1|1,x,d);
tr[p].v=(tr[p<<1].v*tr[p<<1|1].v)%mod;
return ;
}
}
ll phi[maxnn],is[maxnn],len;
void init() {
for(int i=2; i<=1e5+100; i++) {
if(!is[i]) {
phi[++len]=i;
}
for(int j=1; j<=len&&(phi[j]*i<=1e5+100); j++) {
is[phi[j]*i]=1;
if(i%phi[j]==0) break;
}
}
}
ll a[maxnn];
ll res[maxnn];
ll p,n,q;
struct nodee {
ll id,pos,v;
} ans[maxnn];
bool cmp(nodee a,nodee b) {
return a.pos<b.pos;
}
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline ll R() {
char t;
ll x=0;
int f=1;
t=GC;
while(!isdigit(t)) {
if(t=='-') f=-1;
t=GC;
}
while(isdigit(t)) {
x=x*10+t-48;
t=GC;
}
return x*f;
}
void fen(int v) {
ll tmp=a[v];
for(ll i=1; (i<=len)&&(phi[i]<=sqrt(a[v])); i++) {
if(tmp%phi[i]==0) {
while(tmp%phi[i]==0) {
add(1,phi[i],1);
tmp/=phi[i];
}
}
}
if(tmp>1) {
add(1,tmp,1);
}
}
ll s[maxnn];
int main() {
init();
n=R();
q=R();
build(1,1,100100);
for(int i=1; i<=n; i++) {
a[i]=R();
}
for(int i=1; i<=q; i++) {
ans[i].pos=R();
ans[i].v=R();
ans[i].id=i;
}
sort(ans+1,ans+1+q,cmp);
int j=0;
for(int i=1; i<=q; i++) {
while((j<=n)&&(j<ans[i].pos)) {
j++;
fen(j);
}
ll aa=1;
aa=get(1,1,ans[i].v);
s[ans[i].id]=aa%mod;
}
for(int i=1; i<=q; i++) {
printf("%lld\n",s[i]%mod);
}
}
C.生物
(biol.c/.cpp/.in/.out)
问题描述
一个生态系统中有 种生物,它们形成了食物链和食物网。这 种生物中,一些是生产者,
不需要吃其他生物就能生存;剩下的一些是消费者,必须吃其他的一些生物才能生存。
一种生物的重要性定义为,如果这种生物灭绝,将会导致包括自身在内的多少种生物灭绝。
一种消费者生物,如果它的所有食物都灭绝,则这种生物也会灭绝。
一种生物的后效性定义为,如果这种生物灭绝,引发的灭绝事件将会持续多少个单位时间。
一种消费者生物,如果它的最后一种食物在上个单位时间灭绝,则它会在当前这个单位时间
灭绝。
现在的任务是计算每种生物的重要性和后效性。
输入格式
输入文件biol.in。
第一行两个整数 n,m,表示生物的种类数和食物关系数量。
接下来m 行,每行两个整数 a,b,表示第 a种生物可以以第b 种生物为食。保证不会出现
任何一种生物直接或间接吃自己的情况,同一条关系保证不会重复出现。不吃其他任何生物
的生物都是生产者。
输出格式
输出文件biol.out。
输出n 行,第i 行两个整数 c d,分别是表示第 种生物的重要性和后效性。
输入输出样例1
见下发的文件biol-sample1.in和biol-sample1.ans。