Codeforces Round #369 (Div. 2)

来源:互联网 发布:淘宝怎么买弹簧刀 编辑:程序博客网 时间:2024/06/08 07:14

A:略

B:

题意:给出n * n的矩阵,求一个数x,使得将矩阵中的所有0替换成x后,能使得矩阵每一行的数的和、每一列的数的和、分别两个对角线的数的和,值都相等。

题解:解方程。对于每行每列每条对角线,我求出总和 及 0个数,取两个和不相同的行或列或对角线,解方程。(原谅我的渣代码)

#include <cstdio>#include <cmath>#include <queue>#include <stack>#include <iostream>#include <cstring>#include <algorithm>#define LL long long#define loop(a,b,c) for(int a=b;a<=c;a++)#define rloop(a,b,c) for(int a=b;a>=c;a--)#define clr(a,b) memset(a,b,sizeof a)#define sd(x) scanf("%d",&x)#define sf(x) scanf("%lf",&x)#define ss(x) scanf("%s",x)#define x first#define y second#define inf 0x3f3f3f3f#define maxn 200005using namespace std;LL arr[505][505];LL sum_row[505];LL sum_col[505];LL Left,Right,l,r;int row[505];int col[505];int n;bool judge(LL ans,int t1,int t2){int flag = 1;       LL k = sum_row[t1] + 1LL*row[t1]*ans;            //cout<<k<<endl;loop(i,1,n){if(sum_row[i] + 1LL*row[i]*ans !=k || sum_col[i] + 1LL*col[i]*ans!=k)flag = 0;}if(Left + 1LL*l*ans!=k || Right + 1LL*r*ans!=k)flag = 0;return flag;}void solve(){cin>>n;loop(i,1,n) loop(j,1,n) cin>>arr[i][j];loop(i,1,n){loop(j,1,n){sum_col[j] += arr[i][j];sum_row[i] += arr[i][j];if(i==j) Left += arr[i][j];if(i==n-j+1) Right += arr[i][j];if(arr[i][j]==0){row[i] ++,col[j]++;if(i==j) l++;if(i==n-j+1) r++;}}}int t1 =1,t2 = -1;int flag = 0;LL k = sum_row[1];loop(i,2,n){if(sum_row[i] != k){flag  = 1;t2 = i;break;}}if(t2==-1){loop(i,1,n){if(sum_col[i] != k){flag  = 2;t2 = i;break;}}if(t2==-1){if(Left != k){flag  = 3;t2 = 0;}else if(Right != k ){flag  = 4;t2 = 0;}}}//cout<<flag<<" "<<t1<<" "<<t2<<endl;if(t2!=-1){LL b,a;if(flag==1)a = 1LL*row[t1] - 1LL*row[t2],b = 1LL*sum_row[t2] - 1LL*sum_row[t1];if(flag==2)a = 1LL*row[t1] - 1LL*col[t2],b = 1LL*sum_col[t2] - 1LL*sum_row[t1];if(flag==3)a = 1LL*row[t1] - 1LL*l,b = 1LL*Left - 1LL*sum_row[t1];if(flag==4)a = 1LL*row[t1] - 1LL*r,b = 1LL*Right - 1LL*sum_row[t1];        //cout<<a<<" "<<b<<endl;        //cout<<row[t1] - row[t2]<<" "<<row[t1]<<" "<<row[t2]<<endl;if(   a==0 || b/a < 0||b%a!=0)cout<<-1<<endl;else{LL ans = b/a;if(!judge(ans,t1,t2))cout<<"-1"<<endl;elsecout<<ans<<endl;}}else{if(!judge(1,1,2))cout<<"-1"<<endl;elsecout<<1<<endl;}}int main(){    //freopen("data.txt","r",stdin);    solve();    return 0;}
D:

题意:有一个图,有n个顶点,给出每个顶点的对应边,即 顶点i单向连接顶点a[i],我们可以任意改变其中所有边的方向(至多改变一次),为了使得图无环,那么改变的方案有多少?

题解:对于每一个环,如果有 ki 个顶点,改变方案就是 res = (2 ^ ki - 2 ) * 2 ^ ( n - sum(ki) ) (i=1,2,3....),为什么?因为对于所有环,都不会存在两两相交的情况,两两相交的意思是两个环公共一个或一个以上的顶点,那么对于环中的顶点,不妨让所有边的方向都是“逆时针”,那么逆时针的取法就是 =  C(ki,1) + C(ki,2) + ... C(ki,n-1) = 2 ^ ki - 2 ,剩下的不构成环的元素 有 n - sum(ki)个,对这些元素就有 2 ^ (n -  sum( ki ) )个方案;

。。。我用了dij + 并查集  + 快速幂 去做这道题,虽然过了,但是跑得奇慢。。。。

#include <cstdio>#include <cmath>#include <queue>#include <iostream>#include <cstring>#include <algorithm>#define LL long long#define loop(a,b,c) for(int a=b;a<=c;a++)#define rloop(a,b,c) for(int a=b;a>=c;a--)#define clr(a,b) memset(a,b,sizeof a)#define sd(x) scanf("%d",&x)#define sf(x) scanf("%lf",&x)#define ss(x) scanf("%s",x)#define x first#define y second#define inf 0x3f3f3f3f#define maxn 200005using namespace std;const LL mod = 1e9+7;typedef pair<int,int> pii;int f[maxn+100];int to[maxn+100];int d[maxn+100];struct edge{int to,cost;edge(){}edge(int _to,int _cost){to = _to;cost = _cost;}};priority_queue<pii,vector<pii>,greater<pii> > Q;vector<edge> G[maxn];void addedge(int u,int v,int c){G[u].push_back(edge(v,1));G[v].push_back(edge(u,1));}void dij(int s){fill(d,d+maxn,inf);d[s] = 0;Q.push(pii(0,s));while(!Q.empty()){pii p = Q.top();Q.pop();int v = p.y;//if(d[v] < p.first) continue;for(vector<edge>::iterator it = G[v].begin();it!=G[v].end();it++){edge e = *it;if(d[e.to] > d[v] + e.cost){Q.push(pii(d[e.to],e.to));d[e.to]  = d[v] + e.cost;}}}}void init(){loop(i,1,maxn) f[i] = i;}int getf(int x){return f[x]==x?f[x]:getf(f[x]);}void unionset(int u,int v){int a = getf(u);int b = getf(v);if(a!=b)f[b] = a;}bool same(int u,int v){return getf(u)==getf(v);}LL quick_mod(LL x,LL n){LL res = 1;while(n){if(n&1) res = 1LL*res*x%mod;x = 1LL*x*x%mod;n>>=1;}return res;}void solve(){init();int n,k,tmp = 0;sd(n);k = n;LL ans = 1;loop(i,1,n){scanf("%d",&to[i]);if(same(i,to[i])){dij(i);tmp = d[to[i]] + 1;k -= tmp;ans = 1LL* ans * (quick_mod(2,tmp) - 2) % mod;}unionset(i,to[i]);addedge(i,to[i],1);}ans = 1LL * ans * quick_mod(2,k) %mod;printf("%I64d\n",ans);}int main(){solve();}

献上别人的代码,思路是一样的,但是我太菜了,没想到这样去处理。。。
#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#include <vector>#include <string>#include <map>#include <set>#include <cassert>using namespace std;#define rep(i,a,n) for (int i=a;i<n;i++)#define per(i,a,n) for (int i=n-1;i>=a;i--)#define pb push_back#define mp make_pair#define all(x) (x).begin(),(x).end()#define fi first#define se second#define SZ(x) ((int)(x).size())typedef vector<int> VI;typedef long long ll;typedef pair<int,int> PII;const ll mod=1000000007;ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}// headconst int N=201000;int n,a[N],te,vis[N];ll ret=1;int main() {scanf("%d",&n);rep(i,1,n+1) scanf("%d",a+i); te=n;rep(i,1,n+1) if (vis[i]==0) {int x=i;while (1) {vis[x]=i;x=a[x];if (vis[x]) break;}if (vis[x]!=i) continue;int cyc=0,y=x;while (1) {y=a[y]; ++cyc; --te;if (y==x) break;}ret=ret*(powmod(2,cyc)-2)%mod;}ret=ret*powmod(2,te)%mod;printf("%lld\n",ret);}


0 0
原创粉丝点击