题目链接:https://codeforces.com/contest/1220
这题我写复杂了,直接m[1][2]*m[1][3]/m[2][3]=a[1]*a[1]就可以了。
我求第一行的gcd,然后枚举这个gcd的因子去了。。。
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e3+10;
ll a[N][N];
ll ans[N];
int n;
void cal(ll t)
{
ans[1]=t;
for(int i=2;i<=n;++i)ans[i]=a[1][i]/t;
bool f=1;
for(int i=1;i<=n&&f;++i)
{
for(int j=1;j<=n&&f;++j)
{
if(i==j) continue;
else {
if(ans[i]*ans[j]!=a[i][j]) f=0;
}
}
}
if(f)
{
for(int i=1;i<=n;++i) printf("%lld ",ans[i]);
exit(0);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)scanf("%lld",&a[i][j]);
}
ll gc=a[1][1];
for(int j=2;j<=n;++j)
{
gc=gcd(gc,a[1][j]);
}
for(int k=1;k*k<=gc;++k)
{
if(gc%k==0)
{
cal(k);
cal(gc/k);
}
}
//for(int i=1;i<=n;++i) printf("%lld ",ans[i]);
}
水题。。
#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=5e5+10;
char s[N];
int a[N],mi[N];
int main()
{
cin>>s+1;
int n=strlen(s+1);
mi[0]=0x3f3f3f3f;
for(int i=1;i<=n;++i)
{
a[i]=s[i]-'a';
mi[i]=min(mi[i-1],a[i]);
}
for(int i=1;i<=n;++i)
{
if(mi[i-1]
题意:给你n个值,任意两个点只要满足|i-j|那么i和j就可以连一条边。。问如何去掉最少的值使得这个图是二分图?
判定二分图的基本方法:不存在奇环。但是可以得知如果有一个差值,d,那么2*d4*d,6*d....(偶数倍)是不能共存的。
那么换种思路:假如1存在,那么能与1共存的有3,5,7,9,11
2存在,能与2共存的有,6,10,14,。。。
3 存在,能与3共存的有9,15,21....
简单观察得:二进制下,最后一个1的位置相同的是可以存在一起的(半蒙带猜)
#include
using namespace std;
const int N=2e5+10;
typedef long long ll;
ll a[N];
int num[70];
int n;
vectorG[70];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1;i<=n;++i)
{
ll x=a[i];
for(int j=0;j<=64;++j)
{
if((x>>j)&1) {
G[j].push_back(x);
num[j]++;break;
}
}
}
int ans=num[0];
int id=0;
for(int i=0;i<=64;++i)
{
if(num[i]>ans)
{
ans=num[i],id=i;
}
}
printf("%d\n",n-ans);
for(int i=0;i<=64;++i)
{
if(i==id) continue;
for(ll v:G[i]) printf("%lld ",v);
}
}
题意:给n个点和m条边,给n个点的权值。
给你一个起点,s。现从s点出发,经历一些点,并加上对应的点的权值。
条件:同一边不能连续走两次。
做法:tarjan缩点。然后第一次dfs去dp,D从s走不经历度为1的强连通能得到的最大权值
第二次dfs就直接走,拿之前的最大权值走,直到走完所有图,求最大值即可。
挺思维的
#include
using namespace std;
typedef long long ll;
const int N=2e5+10;
int dfn[N],low[N],cnt,bcc[N],index,bccnum;
int sz[N];
ll val[N],dp[N];
int top=0;
int sta[N];
int n,m;
vectorG[N],g[N];
void tarjan(int root,int fa)
{
dfn[root]=low[root]=++index;
sta[++top]=root;
for(int v:g[root])
{
if(v==fa) continue;
if(!dfn[v])
{
tarjan(v,root);
low[root]=min(low[root],low[v]);
}
else low[root]=min(low[root],dfn[v]);
}
if(low[root]==dfn[root])
{
bccnum++;
int x;
do
{
x=sta[top--];
bcc[x]=bccnum;
sz[bccnum]++;
dp[bccnum]+=val[x];
}while(x!=root);
}
}
void dfs(int u,int fa)
{
for(int v:G[u])
{
if(v==fa) continue;
dfs(v,u);
if(sz[v]>1)
{
dp[u]+=dp[v];
dp[v]=0;
sz[u]+=sz[v];
}
}
}
ll ans=0;
ll d[N];
void dfs1(int u,int fa,ll v)
{
d[u]=dp[u]+v;
ans=max(ans,d[u]);
for(int v:G[u])
{
if(v==fa) continue;
dfs1(v,u,d[u]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%lld",&val[i]);
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
int s;
scanf("%d",&s);
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i,0);
for(int i=1;i<=n;++i)
for(int v:g[i])
if(bcc[i]!=bcc[v])
{
G[bcc[i]].push_back(bcc[v]);//有向边?
//G[bcc[v]].push_back(bcc[i]);
}
s=bcc[s];
dfs(s,0);
dfs1(s,0,0);
printf("%lld\n",ans);
return 0;
}