以后养成一个好习惯,每天做一套agc。
[AGC002A] Range Product
入门。
int a,b;
int main(){
scanf("%d%d",&a,&b);
if(a>b)swap(a,b);
if(a<=0&&b>=0)puts("Zero");
else if(a>0||((min(0,b)-a)&1))puts("Positive");
else puts("Negative");
return 0;
}
[AGC002B] Box and Ball
普及-。
int n,m,a[100010],cnt[100010];
bool v[100010];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)cnt[i]=1;
v[1]=true;
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
cnt[x]--;cnt[y]++;v[y]|=v[x];
if(cnt[x]==0)v[x]=false;
}
int ans=0;
for(int i=1;i<=n;i++)ans+=v[i];
printf("%d\n",ans);
return 0;
}
[AGC002C] Knot Puzzle
真正普及-。
int n,pos=1,l,a[100010];
int main(){
scanf("%d%d",&n,&l);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=2;i<=n;i++){
if(a[i]+a[i-1]>a[pos]+a[pos-1])pos=i;
}
if(a[pos]+a[pos-1]>=l){
puts("Possible");
for(int i=2;i<pos;i++)printf("%d\n",i-1);
for(int i=n;i>=pos;i--)printf("%d\n",i-1);
}
else puts("Impossible");
return 0;
}
[AGC002D] Stamp Rally
大概两种写法。
首先看这个最大编号最小直接二分,然后可以写Kruskal重构树,也可以整体二分+可持久化并查集。我写的后者。然后并查集加了个路径压缩调了半天。
struct node{
int u,v;
}edge[100010];
int n,m,Q,ans[100010],fa[100010],siz[100010];
int find(int x){
return fa[x]==x?fa[x]:find(fa[x]);
}
struct ques{
int x,y,z,id;
}q[100010],q1[100010],q2[100010];
pair<int,int> stk[100010];
int top;
void merge(int x,int y){
x=find(x);y=find(y);
if(x==y)return;
if(siz[x]<siz[y])swap(x,y);
fa[y]=x;siz[x]+=siz[y];
stk[++top]=make_pair(x,y);
}
void solve(int L,int R,int l,int r){
if(l==r){
for(register int i=L;i<=R;i++)ans[q[i].id]=l;
int x=find(edge[l].u),y=find(edge[l].v);
if(x==y)return;
if(siz[x]<siz[y])swap(x,y);
fa[y]=x;siz[x]+=siz[y];
return;
}
int mid=(l+r)>>1,cnt1=0,cnt2=0;
for(register int i=l;i<=mid;i++)merge(edge[i].u,edge[i].v);
for(register int i=L;i<=R;i++){
int x=find(q[i].x),y=find(q[i].y);
if(x==y){
if(siz[x]>=q[i].z)q1[++cnt1]=q[i];
else q2[++cnt2]=q[i];
}
else{
if(siz[x]+siz[y]>=q[i].z)q1[++cnt1]=q[i];
else q2[++cnt2]=q[i];
}
}
for(register int i=1;i<=cnt1;i++)q[i+L-1]=q1[i];
for(register int i=1;i<=cnt2;i++)q[i+cnt1+L-1]=q2[i];
while(top){
fa[stk[top].second]=stk[top].second;
siz[stk[top].first]-=siz[stk[top].second];
top--;
}
solve(L,L+cnt1-1,l,mid);
solve(L+cnt1,R,mid+1,r);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(register int i=1;i<=n;i++)fa[i]=i,siz[i]=1;
for(register int i=1;i<=m;i++)cin>>edge[i].u>>edge[i].v;
cin>>Q;
for(register int i=1;i<=Q;i++){
cin>>q[i].x>>q[i].y>>q[i].z;q[i].id=i;
}
solve(1,Q,1,m);
for(register int i=1;i<=Q;i++)cout<<ans[i]<<'\n';
return 0;
}
[AGC002E] Candy Piles
很妙妙的题。很想不到的转化。
首先看这个条件很蛋疼,我们考虑转换一下。
把 \(a\) 从大到小排序,然后整成一个二维坐标系的形式(从下到上)。然后随手造组样例举例子:
4
2 7 4 3
排序后变成7 4 3 2
。然后转化成二维坐标系:
00
000
0000
0000000
然后我们就可以很方便地表示两种操作。我们从左下角开始,如果去掉最大就是向上移动一格,全都去掉一个就是向右移动一格。终止条件是边界,显然是必败情况。所以我们可以把这个东西染个色(√为必胜,×为必败):
××
×√×
√×√×
×√×√×××
然后发现这玩意在内部是√
和×
交错的。规律就找出来了。具体怎么求可以找到以左下角为中心的最大的正方形,左下角和右上角的状态显然一样。然后看正方形右上角上方和右方有多少个点。如果全是奇数那么先手必胜,反之先手必败。
int n,a[100010];
bool cmp(int a,int b){
return a>b;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
if(a[i+1]<i+1){
int j=0;
while(a[j+i+1]==i)j++;
if(((a[i]-i)&1)||(j&1))puts("First");
else puts("Second");
return 0;
}
}
}
[AGC002F] Leftmost Ball
小清新组合数 dp。
首先显然是个 \(n^2\) dp。那么设 \(dp_{i,j}\) 为放了 \(i\) 个白球, \(j\) 种颜色的球的方案数。转移考虑放白球和放颜色球。
然后我们假设有 \(n\times k\) 个空位放球,每次考虑最左边的合法空位能放什么。
- 放白球:只放在最左边的空位,方案显然 \(dp_{i-1,j}\) 。
- 放颜色球:从剩下的 \(n-j+1\) 种颜色里选一个,然后这有颜色的 \(k-1\) 个球里,第一个球的位置是定死在最左边的空位的,然后剩下的可以随便放。剩下 \(n\times k-i-1-(j-1)\times(k-1)\) 个空位,放 \(k-2\) 个球,就是个组合数。
const int mod=1000000007;
int n,k,dp[2010][2010],jc[4000010],inv[4000010];
int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return ans;
}
int C(int n,int m){
if(n<m)return 0;
return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
scanf("%d%d",&n,&k);jc[0]=inv[0]=1;
if(k==1){
puts("1");return 0;
}
for(int i=1;i<=n*k;i++)jc[i]=1ll*jc[i-1]*i%mod;
inv[n*k]=qpow(jc[n*k],mod-2);
for(int i=n*k-1;i>=1;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
for(int i=0;i<=n;i++)dp[i][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
dp[i][j]=(dp[i][j]+dp[i-1][j]+1ll*(n-j+1)*dp[i][j-1]%mod*C(n*k-i-1-(j-1)*(k-1),k-2)%mod)%mod;
}
}
printf("%d\n",dp[n][n]);
return 0;
}
完了。
标签:AGC002,return,记录,int,pos,else,VP,100010,dp From: https://www.cnblogs.com/gtm1514/p/16881593.html