chrisl gjeztor Amledza
prof ovelmizer
dos carm ammeidha alzenghar
kawy may noxial gjeztor
Rupieilla vas photreywz idha
[AGC012A] AtCoder Group Contest
普及题。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,a[300010];
long long ans;
int main(){
scanf("%d",&n);
for(int i=1;i<=3*n;i++)scanf("%d",&a[i]);
sort(a+1,a+3*n+1);
int l=1,r=3*n;
for(int i=1;i<=n;i++){
l++;r--;ans+=a[r];r--;
}
printf("%lld\n",ans);
return 0;
}
[AGC012B] Splatter Painting
普及题。倒着扫回来。第一发 t 了,加个剪枝,存一下每个节点距离多少都被染了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,m,q,col[100010],dis[100010];
struct node{
int v,next;
}edge[200010];
int t,head[100010];
void add(int u,int v){
edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
struct Ques{
int v,d,c;
}ques[100010];
void dfs(int x,int c,int d){
if(!col[x])col[x]=c;
if(!d||dis[x]>=d)return;
dis[x]=d;
for(int i=head[x];i;i=edge[i].next)dfs(edge[i].v,c,d-1);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
scanf("%d",&q);
for(int i=1;i<=q;i++)scanf("%d%d%d",&ques[i].v,&ques[i].d,&ques[i].c);
for(int i=q;i>=1;i--){
dfs(ques[i].v,ques[i].c,ques[i].d);
}
for(int i=1;i<=n;i++)printf("%d\n",col[i]);
return 0;
}
[AGC012C] Tautonym Puzzle
又是构造。感觉挺智慧的。感觉洛谷题解除了第一篇和第三篇讲 spj 怎么写的全都不如官方题解。
首先在前面顺序铺上 \(1-100\),后边铺一个排列,答案就可以变成上升子序列个数,空串也算一个。于是就要得到 \(n+1\) 个(因为算了空串)。
那么从小到大插数字。每次有两种选择:前面加一个,个数 \(+1\);后面加一个,个数 \(\times 2\)(因为算了空串所以不用 \(+1\))。那就相当于初值是 \(1\),每次操作 \(+1/\times 2\),拼到 \(n\)。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
long long n;
int p[210],q[210];
int main(){
scanf("%lld",&n);int x=0;n++;
while(n>1){
if(n&1)x++,p[++p[0]]=x,n--;
else x++,q[++q[0]]=x,n>>=1;
}
printf("%d\n",x<<1);
for(int i=1;i<=x;i++)printf("%d ",i);
for(int i=1;i<=q[0];i++)printf("%d ",q[i]);
for(int i=p[0];i>=1;i--)printf("%d ",p[i]);
return 0;
}
[AGC012D] Colorful Balls
水题。建议和 C swap 一下。
首先看见这种东西想图上连通块。那有一个 \(O(n^2)\) 的直接连边冲的做法。
然后发现连边可以只有每个颜色最小的一个和当前颜色其他连边,每种颜色最小的和全局最小连边,然后全局最小所在颜色和全局次小颜色连边。那找到这些就可以线性了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int mod=1000000007,inf=2147483647;
int n,x,y,sum,ans=1,jc[200010],inv[200010],mn[200010],c[200010],w[200010],cnt[200010];
bool v[200010];
int main(){
scanf("%d%d%d",&n,&x,&y);jc[0]=inv[0]=inv[1]=1;
for(int i=2;i<=n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;i++)jc[i]=1ll*jc[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod,mn[i]=inf;
for(int i=1;i<=n;i++)scanf("%d%d",&c[i],&w[i]),mn[c[i]]=min(mn[c[i]],w[i]);
int minn=inf,sec=inf;
for(int i=1;i<=n;i++){
if(mn[i]<=minn)sec=minn,minn=mn[i];
else if(mn[i]<=sec)sec=mn[i];
}
for(int i=1;i<=n;i++){
if(mn[c[i]]+minn>y)continue;
if(mn[c[i]]+w[i]<=x)cnt[c[i]]++,sum++;
else if((mn[c[i]]==minn?sec:minn)+w[i]<=y)cnt[c[i]]++,sum++;
}
for(int i=1;i<=n;i++)ans=1ll*ans*inv[cnt[i]]%mod;
ans=1ll*ans*jc[sum]%mod;
printf("%d\n",ans);
return 0;
}
[AGC012E] Camel and Oases
考过。当时暴力 + 特判艹过去的。现在看来还要重来。很神仙的题。所以我就是 fw 到一定程度了。
首先把所有可能的 \(V\) 和每个点在每个 \(V\) 能到达的左右端点扫出来。然后状压一下,求出使用 \(S\) 内的 \(V\) 时在点 \(1\) 和点 \(n\) 能向左右走的最远距离。统计答案的时候扫所有集合拼起来看能不能到就行了。
代码调半天调不出,先摆。
[AGC012F] Prefix Median
一看到这种数据范围小的 dp 就完全蒙掉。
首先把 \(a\) 排序。先假设两两不同。
观察一些性质。考虑每次操作是序列中插入两个 \(a\),那么当前的中位数 \(b_i\) 变成 \(b_{i+1}\) 的时候只会有三种可能:变成前驱/后继/不变。
然后考虑什么数能放在 \(b_i\) 上。放到 \(b_i\) 上的数的值域一定在 \([i,2n-i]\) 之间。
于是我们就有了如下的两条性质:对于 \(b_i\),有:
- \(a_i\le b_i\le a_{2n-i}\)
- 不存在 \(j\) 使得 \(b_i<b_j<b_{i+1}\) 或 \(b_i>b_j>b_{i+1}\)。
考虑计数。对于第一个条件,我们从后往前填数,每次选两个数放进可行集合。对于第二个条件,我们填入 \(b_i\) 的时候需要考虑所有后边的数,\(b_i\) 不能被它们的区间所包含。
这样我们就变成了这样的过程:初始有一个数 \(a\),每次向集合内加两个数,然后选择一个数 \(x\),把所有 \(a,x\) 之间的数去掉,给 \(a\) 赋值 \(x\),问最后方案数。
容易发现我们只关注当前位置左边和右边剩下多少个数。那么设 \(dp_{i,j,k}\) 为第 \(i\) 位左边 \(j\) 个右边 \(k\) 个的方案数,转移讨论向左走或者向右走。对于重复的,可以发现加入重复的点是无效的,直接忽略就行了。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int mod=1000000007;
int n,a[110],dp[110][110][110];
int main(){
scanf("%d",&n);
for(int i=1;i<(n<<1);i++)scanf("%d",&a[i]);
sort(a+1,a+n+n);
dp[n][0][0]=1;
for(int i=n-1;i>=1;i--){
int ret=(a[i]!=a[i+1]),tmp=(a[2*n-i]!=a[2*n-i-1]);
for(int j=0;j<=(n<<1);j++){
for(int k=0;k<=(n<<1);k++){
dp[i][j+ret][k+tmp]=(dp[i][j+ret][k+tmp]+dp[i+1][j][k])%mod;
for(int l=0;l<j+ret;l++)dp[i][l][k+tmp+1]=(dp[i][l][k+tmp+1]+dp[i+1][j][k])%mod;
for(int l=0;l<k+tmp;l++)dp[i][j+ret+1][l]=(dp[i][j+ret+1][l]+dp[i+1][j][k])%mod;
}
}
}
int ans=0;
for(int i=0;i<=(n<<1);i++)for(int j=0;j<=(n<<1);j++)ans=(ans+dp[1][i][j])%mod;
printf("%d\n",ans);
return 0;
}
标签:AGC012,int,题解,scanf,200010,++,using,include
From: https://www.cnblogs.com/gtm1514/p/17231232.html