Comet OJ - Contest #0

  A:化成x-√n=y+z-√4yz的形式,则显然n是完全平方数时有无数组解,否则要求n=4yz,暴力枚举n的因数即可。注意判断根号下是否不小于0。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define P 1000000007
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
	while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
signed main()
{
	int T=read();
	while (T--)
	{
		int n=read();
		int w=sqrt(n);
		if (w*w==n||(w+1)*(w+1)==n||(w-1)*(w-1)==n) cout<<"infty"<<endl;
		else
		{
			if (n%4) cout<<0<<‘ ‘<<0<<endl;
			else
			{
				n/=4;
				int cnt=0,ans=0;
				for (int i=1;i*i<=n;i++)
				if (n%i==0)
				{
					if (i+n/i>w) cnt++,ans=(ans+1ll*n*(i+n/i))%P;
				}
				cout<<cnt<<‘ ‘<<ans<<endl;
			}
		}
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  B:f[i][j][k]表示第i步后左边有j个已访问城市右边有k个已访问城市的概率,转移显然。虽然是在一个环上,但不看成环也没有问题,最后对n取min即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define P 1000000007
#define N 510
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
	while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int T,f[N][N][N];
int ksm(int a,int k)
{
	int s=1;
	for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P;
	return s;
}
signed main()
{
	T=read();
	while (T--)
	{
		int n=read(),m=read(),k=read(),p=read(),q=read();
		for (int i=1;i<=m;i++)
			for (int j=0;j<i;j++)
				for (int k=0;k<i;k++)
				f[i][j][k]=0;
		f[1][0][0]=1;
		for (int i=1;i<m;i++)
			for (int x=0;x<i;x++)
				for (int y=0;y<i;y++)
				f[i+1][max(x-1,0)][y+1]=(f[i+1][max(x-1,0)][y+1]+1ll*p*f[i][x][y])%P,
				f[i+1][x+1][max(y-1,0)]=(f[i+1][x+1][max(y-1,0)]+1ll*q*f[i][x][y])%P,
				f[i+1][x][y]=(f[i+1][x][y]+1ll*(100-p-q)*f[i][x][y])%P;
		int ans=0;
		for (int x=0;x<m;x++)
			for (int y=0;y<m;y++)
			ans=(ans+1ll*f[m][x][y]*ksm(min(x+y+1,n),k))%P;
		cout<<ans<<endl;
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  C:容易发现相当于要求两点间存在至少两条边不重复路径,也即两点在同一边双内,用LCT维护边双即可。具体见https://www.cnblogs.com/Gloid/p/10056499.html。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 1000010
#define lson tree[k].ch[0]
#define rson tree[k].ch[1]
#define lself tree[tree[k].fa].ch[0]
#define rself tree[tree[k].fa].ch[1]
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,q,fa[N],fa2[N],size[N];
ll ans;
struct data{int ch[2],fa,rev;
}tree[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int find2(int x){return fa2[x]==x?x:fa2[x]=find2(fa2[x]);}
void rev(int k){if (k) swap(lson,rson),tree[k].rev^=1;}
void down(int k){if (tree[k].rev) rev(lson),rev(rson),tree[k].rev=0;}
int whichson(int k){return rself==k;}
bool isroot(int k){return lself!=k&&rself!=k;}
void push(int k){if (!isroot(k)) push(tree[k].fa);down(k);}
void move(int k)
{
    int fa=tree[k].fa,gf=tree[fa].fa,p=whichson(k);
    if (!isroot(fa)) tree[gf].ch[whichson(fa)]=k;tree[k].fa=gf;
    tree[fa].ch[p]=tree[k].ch[!p],tree[tree[k].ch[!p]].fa=fa;
    tree[k].ch[!p]=fa,tree[fa].fa=k;
}
void splay(int k)
{
    push(k);
    while (!isroot(k))
    {
        int fa=tree[k].fa;
        if (!isroot(fa))
            if (whichson(fa)^whichson(k)) move(k);
            else move(fa);
        move(k);
    }
}
void access(int k){for (int t=0;k;t=k,k=tree[k].fa=find(tree[k].fa)) splay(k),tree[k].ch[1]=t;}
void makeroot(int k){access(k),splay(k),rev(k);}
void link(int x,int y){makeroot(x),tree[x].fa=y,fa2[find2(x)]=find2(y);}
ll C(int x,int y){return 1ll*x*(x-1)/2;}
void dfs(int k,int x)
{
    if (!k) return;
    if (find(k)!=x)
	{
		ans-=C(size[x],2);ans-=C(size[find(k)],2);
		size[x]+=size[find(k)];
		ans+=C(size[x],2);
		fa[find(k)]=x;
	}
    dfs(lson,x),dfs(rson,x);
}
void addedge(int x,int y)
{
    if (find2(x)!=find2(y)) link(x,y);
    else
    {
        makeroot(x),access(y),splay(y);
        dfs(tree[y].ch[0],y);tree[y].ch[0]=0;
    }
}
int main()
{
	int T=read();
	while (T--)
	{
    	n=read(),m=read();
    	ans=0;ll tot=0;
    	for (int i=1;i<=n;i++) fa[i]=i,fa2[i]=i,size[i]=1,tree[i].ch[0]=tree[i].ch[1]=tree[i].fa=tree[i].rev=0;
    	for (int i=1;i<=m;i++)
    	{
        	int x=find(read()),y=find(read());
        	if (x!=y) addedge(x,y);
        	tot^=i*ans;
	    }
	    cout<<tot<<endl;
	}
    return 0;
}

  D:考虑暴力,即枚举每道题的做法,然后给每道题一个贪心顺序,大约是T*86*6!的过不掉。注意到值域很小,考虑以此dp,并把贪心顺序放到外层,即f[S][i][j]表示已做完S集合的题目,第一个人最后做题时刻为j,第二个人最后做题时刻为k时,第三个人最早的最后做题时刻,转移考虑下一步贪心的做哪个题以及怎么做即可,大约是T*26*1802*6*8。虽然复杂度看起来仍然非常爆炸,但容易发现很多状态都是无法到达的,转移时先看一下当前状态dp值是否合法即可,这样内部的6*8几乎可以无视。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int a[10][10],f[1<<6][200][200],size[1<<6];
int main()
{
	int T=read();
	for (int i=1;i<(1<<6);i++) size[i]=size[i^(i&-i)]+1;
	while (T--)
	{
		for (int i=0;i<6;i++)
		cin>>a[i][1]>>a[i][2]>>a[i][4]>>a[i][3]>>a[i][5]>>a[i][6]>>a[i][7];
		memset(f,42,sizeof(f));f[0][0][0]=0;
		int ans=0,ans2=0;
		for (int i=0;i<(1<<6);i++)
		{
			for (int j=0;j<=180;j++)
				for (int k=0;k<=180;k++)
				if (f[i][j][k]<=180)
				{
					for (int x=0;x<6;x++) if (!(i&(1<<x)))
					{
						int u=i|(1<<x);
						f[u][min(j+a[x][1],181)][k]=min(f[u][min(j+a[x][1],181)][k],f[i][j][k]);
						f[u][j][min(k+a[x][2],181)]=min(f[u][j][min(k+a[x][2],181)],f[i][j][k]);
						f[u][j][k]=min(f[u][j][k],f[i][j][k]+a[x][4]);
						int v=min(max(max(j,k),f[i][j][k])+a[x][7],181);
						f[u][v][v]=min(f[u][v][v],v);
						v=min(max(j,k)+a[x][3],181);
						f[u][v][v]=min(f[u][v][v],f[i][j][k]);
						v=min(max(j,f[i][j][k])+a[x][5],181);
						f[u][v][k]=min(f[u][v][k],v);
						v=min(max(k,f[i][j][k])+a[x][6],181);
						f[u][j][v]=min(f[u][j][v],v);
					}
				}
		}
		for (int i=1;i<(1<<6);i++)
			for (int j=0;j<=180;j++)
				for (int k=0;k<=180;k++)
				if (f[i][j][k]<=180)
				{
					if (size[i]>ans||size[i]==ans&&max(max(j,f[i][j][k]),k)<ans2)
					{
						ans=size[i];
						ans2=max(max(j,f[i][j][k]),k);
					}
				}
		cout<<ans<<‘ ‘<<ans2<<endl;
	}
    return 0;
}

  E:考虑处理出前后缀求LIS用的单调栈。注意到修改一个数后LIS要么不变要么+1,所以维护出有用的前后缀每一对LIS的拼接结果即可。注意还要考虑修改后LIS仍不包含当前数的情况。代码有大量冗余。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
#define ll long long
#define N 100010
#define inf 1000000010
char getc(){char c=getchar();while ((c<‘A‘||c>‘Z‘)&&(c<‘a‘||c>‘z‘)&&(c<‘0‘||c>‘9‘)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1;c=getchar();}
    while (c>=‘0‘&&c<=‘9‘) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,a[N],ans,p[N],q[N],f[N][2],g[N][2],stkx[N],stky[N],cnt;
multiset<int> q1,q2;
int main()
{
	int T=read();
	while (T--)
	{
		n=read();
		for (int i=1;i<=n;i++) a[i]=read();
		q[0]=inf;for (int i=1;i<=n;i++) q[i]=-1;
		g[n+1][0]=0,g[n+1][1]=inf;ans=0;
		for (int i=n;i>=1;i--)
		{
			int l=0,r=ans;
			while (l<=r)
			{
				int mid=l+r>>1;
				if (q[mid]>a[i]) g[i][0]=mid+1,l=mid+1;
				else r=mid-1;
			}
			stkx[i]=g[i][0],stky[i]=q[g[i][0]];
			g[i][1]=q[g[i][0]]=a[i];
			ans=max(ans,g[i][0]);
		}
		cnt=0;q1.clear(),q2.clear();
		p[0]=-1;for (int i=1;i<=n;i++) p[i]=inf;
		if (q[ans]>p[0]) cnt++;
		if (q[ans]>p[0]+1) q1.insert(p[0]);
		if (q[ans-1]>p[0]+1) q2.insert(p[0]);
		f[0][0]=0,f[0][1]=-1;
		int mx=0;
		for (int i=1;i<=n;i++)
		{
			if (q[stkx[i]]>p[ans-stkx[i]]+1) q1.erase(q1.find(p[ans-stkx[i]]));
			if (ans>=stkx[i]+1) if (q[stkx[i]]>p[ans-stkx[i]-1]+1) q2.erase(q2.find(p[ans-stkx[i]-1]));
			if (q[stkx[i]]>p[ans-stkx[i]]) cnt--;
			q[stkx[i]]=stky[i];
			if (q[stkx[i]]>p[ans-stkx[i]]+1) q1.insert(p[ans-stkx[i]]);
			if (ans>=stkx[i]+1) if (q[stkx[i]]>p[ans-stkx[i]-1]+1) q2.insert(p[ans-stkx[i]-1]);
			if (q[stkx[i]]>p[ans-stkx[i]]) cnt++;
			if (!q1.empty()) printf("%d %d\n",ans+1,(*q1.begin())+1);
			else if (cnt) printf("%d %d\n",ans,0);
			else printf("%d %d\n",ans,(*q2.begin())+1);
			int l=0,r=mx;
			while (l<=r)
			{
				int mid=l+r>>1;
				if (p[mid]<a[i]) f[i][0]=mid+1,l=mid+1;
				else r=mid-1;
			}
			mx=max(mx,f[i][0]);
			if (q[ans-f[i][0]]>p[f[i][0]]+1) q1.erase(q1.find(p[f[i][0]]));
			if (ans>=f[i][0]+1) if (q[ans-f[i][0]-1]>p[f[i][0]]+1) q2.erase(q2.find(p[f[i][0]]));
			if (q[ans-f[i][0]]>p[f[i][0]]) cnt--;
			f[i][1]=p[f[i][0]]=a[i];
			if (q[ans-f[i][0]]>p[f[i][0]]+1) q1.insert(p[f[i][0]]);
			if (ans>=f[i][0]+1) if (q[ans-f[i][0]-1]>p[f[i][0]]+1) q2.insert(p[f[i][0]]);
			if (q[ans-f[i][0]]>p[f[i][0]]) cnt++;
		}
	}
    return 0;
}

  F:咕

  没有小裙子呜呜呜

原文地址:https://www.cnblogs.com/Gloid/p/10635364.html

时间: 2024-10-31 08:05:26

Comet OJ - Contest #0的相关文章

Comet OJ - Contest #5

Comet OJ - Contest #5 总有一天,我会拿掉给\(dyj\)的小裙子的. A 显然 \(ans = min(cnt_1/3,cnt_4/2,cnt5)\) B 我们可以感性理解一下,最大的满足条件的\(x\)不会太大 因为当\(x\)越来越大时\(f(x)\)的增长速度比\(x\)的增长速度慢得多 其实可以证明,最大的满足的\(x\)不会超过\(100\) 因为没有任何一个三位数的各位之和大于等于\(50\) 所以我们就直接预处理\(1-99\)所有的合法的 暴力枚举即可 其实

符文能量(Comet OJ - Contest #8)

给Comet OJ打个小广告,挺好用的,比较简洁,给人感觉很好用 Contest #8是我打的第一场本oj比赛,很遗憾A了前两道傻逼题就没思路了,然后就不打算打了....... https://www.cometoj.com/contest/58/problem/C?problem_id=2760 怎么做啊完全不会啊我那么菜,虽然看到是dp但嫌太麻烦就放弃了: 靠后仔细想了想原来这道题很简单: 结构体node e[];储存ai,bi值(当然你用数组我也不拦着),因为合并的方式很特殊,可以不管合并

Comet OJ - Contest #10 B

Comet OJ - Contest #10 B 沉鱼落雁 思维题 题意 : 每个数字最多重复出现三次,有n给数字,让你尽可能的使得相同数字之间的最小距离尽可能大 思路 :分三种情况套路 设 a b c 分别代表出现 一次, 两次, 三次 数字的个数 所有元素至多出现一次,答案为 n,题目规定 所有元素至多出现两次, 例如 1 1 2,可以排列成 1 2 1,所以,答案为 1 例如 1 1 2 2 3,可以排列成 1 2 3 1 2,所有 答案为 2 思考后得出,应该尽可能的把 b 个出现两次的

Comet OJ - Contest #7 解题报告

传送门:https://www.cometoj.com/contest/52 A:签到题 题意:多次询问,每次询问给出一个值域区间[l,r],从这区间范围中选出两个整数(可重复),依次求出这俩数的“最大的最小公倍数”.“最小的最小公倍数”.“最大的最大公约数”.最小的最大公约数. 分析:(1)显然,当区间长度为1时,该问题的答案只能是区间中仅有的那个数. (2)当区间的长度大于1时,最大的最小公倍数,lcmmax =lcm(ar,ar-1) = ar * ar-1: 最小的最小公倍数,lcmmi

Comet OJ - Contest #15

https://cometoj.com/contest/79/problem/D?problem_id=4219 题目描述 ※ 简单版与困难版的唯一区别是粗体字部份和 $v$ 的数据范围. 在双 11 时,心慧精品店有个特别的折价活动如下: 首先,我们定义一个正整数为"好的"当且仅当此数仅由数字 1 构成,举例来说 1, 11, 111, 11111 都是「好的」,但 10.123.321 都是「不好的」. 接着,若一个商品原价为 x,若顾客能把 x 表示为 k 个「好的」数字,那么此

Comet OJ - Contest #15题解

A 双十一特惠 (简单版) n  <=  1e19,   1e9 > 1(8) https://www.cometoj.com/contest/79/problem/A?problem_id=4198 #include<bits/stdc++.h> using namespace std; int main(){ int t; cin >> t; while(t--) { int cnt1 = 0; int n;cin >> n; int pr[] = {1

Comet OJ - Contest #1

A:随便怎么暴力. #include<bits/stdc++.h> using namespace std; #define ll long long #define N 25 char getc(){char c=getchar();while (c!='.'&&c!='#') c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char

Comet OJ Contest #2

A:暴力,显然每两次至少翻一倍. #include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} in

Comet OJ Contest #3

A:签到. #include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 510 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}