C - Counting Stars
无向图求三元环
这里需要一些小小的改动
题目中要求的A结构其实是两个具有一条公共边的三元环
求这样的个数
根据算法我们一开始就是先枚举一条边,这样我们就以第一条边为公共边,找出三元环的个数,然后从这n个中选2个即可,也就是sum⋅(sum−1)/2
#include<cstdio>
#include<vector>
#include<unordered_set>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
vector<int> g[maxn];
unordered_set<ll> st;
int vis[maxn],link[maxn],out[maxn];
int main(){
ll ans,sum;
int n,m,x,y,z,B;
while(scanf("%d%d",&n,&m)!=EOF){
B=sqrt(m);
st.clear();
for(int i=1;i<=n;i++){
g[i].clear();
vis[i]=link[i]=out[i]=0;
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
g[x].push_back(y);
out[x]++;
g[y].push_back(x);
out[y]++;
st.insert((ll)n*x+y); //对于大于根号下m的边不好这样进行判断时候有边相连,速度快而且更加家简便
st.insert((ll)n*y+x);
}
ans=0;
for(int i=1;i<=n;i++){
x=i;
vis[x]=1;
for(int j=0;j<g[x].size();j++){
link[g[x][j]]=x;
}
for(int j=0;j<g[x].size();j++){
sum=0;
y=g[x][j]; //枚举第二个点,第一条边
if(vis[y]) continue;
if(out[y]<=B){
for(int k=0;k<g[y].size();k++){
z=g[y][k];
if(link[z]==x) sum++;
}
}else{
for(int k=0;k<g[x].size();k++){
z=g[x][k];
if(st.find((ll)z*n+y)!=st.end()) sum++;
}
}
ans+=sum*(sum-1)/2;
}
}
printf("%lld\n",ans);
}
return 0;
}
D - Covering
通过dfs产生前10个数,列成方程组的形式结合搞死先生的消元法算出四个系数
之所以是4个可能是因为4*n的缘故把。
ac代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<list>
#include<queue>
#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define MAXN 0x3f3f3f3f3f3f3f3f
#define PI acos(-1.0)
#define E exp(1.0)
using namespace std;
const ll MOD=1e9+7;
const int N=4;
struct node{
ll a[10][10];
}tmp,ans,t;
//#define debug
node matrix(node x,node y ){
node q;
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
q.a[i][j]=0;
for(int k=1;k<=N;k++){
q.a[i][j]=(q.a[i][j]+x.a[i][k]*y.a[k][j]+MOD)%MOD;
}
}
}
return q;
}
void quick_ma(ll n){
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
ans.a[i][j]=0;
}
}
for(int i=1;i<=N;i++) ans.a[i][i]=1;
t=tmp;
while(n){
if(n&1) ans=matrix(ans,t);
n>>=1;
t=matrix(t,t);
}
}
int main()
{
#ifdef debug
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif // debug
ll n;
for(int i=1;i<=N;i++){
for(int j=1;j<=N;j++){
tmp.a[i][j]=0;
}
}
tmp.a[1][1]=1;
tmp.a[1][2]=5;
tmp.a[1][3]=1;
tmp.a[1][4]=-1;
tmp.a[2][1]=1;
tmp.a[3][2]=1;
tmp.a[4][3]=1;
while(scanf("%lld",&n)!=EOF){
if(n==1) printf("1\n");
else if(n==2) printf("5\n");
else if(n==3) printf("11\n");
else if(n==4) printf("36\n");
else{
quick_ma(n-4);
printf("%lld\n",(ans.a[1][1]*36l%MOD+ans.a[1][2]*11l%MOD+ans.a[1][3]*5l%MOD+ans.a[1][4])%MOD);
}
}
return 0;
}
/*
*/
附上搞死先生的消元法“:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=100;
double a[N][N];
double ans[N];
int n;
void swap_r(int q,int p)
{
for(int i=1;i<=n+1;i++)
{
double t=a[p][i];
a[p][i]=a[q][i];
a[q][i]=t;
}
}
void swap_c(int q,int p)
{
for(int i=1;i<=n+1;i++)
{
double t=a[i][p];
a[i][p]=a[i][q];
a[i][q]=t;
}
}
void prt()
{
for(int i=1;i<=n+1;i++)
{
for(int j=1;j<=n+1;j++)
printf("%2.5f ",a[i][j]);
printf("\n");
}
printf("\n");
}
void gs()
{
for(int i=1;i<n;i++)
{
double m=fabs(a[i][i]);
int p=i,q=i;
for(int j=i+1;j<=n;j++)
for(int k=i;k<=n;k++)
if(fabs(a[j][k])>m)
{
m=fabs(a[j][k]);
p=j;
q=k;
}
//cout<<p<<endl;
if(p!=i)
swap_r(p,i);
if(q!=i)
swap_c(q,i);
//prt();
for(int j=i+1;j<=n;j++)
{
if(a[j][i]==0.0) continue;
double t=a[j][i]/a[i][i];
a[j][i]=0.0;
for(int k=i+1;k<=n+1;k++)
a[j][k]-=t*a[i][k];
}
//prt();
}
prt();
}
void red()
{
for(int i=n;i>1;i--)
{
for(int j=i-1;j>=1;j--)
{
if(a[j][i]==0) continue;
double t=a[j][i]/a[i][i];
a[j][i]=0.0;
for(int k=i+1;k<=n+1;k++)
a[j][k]-=t*a[i][k];
}
}
prt();
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
scanf("%lf",&a[i][j]);
for(int i=1;i<=n;i++)
a[n+1][i]=i;
gs();
red();
for(int i=1;i<=n;i++)
ans[(int)a[n+1][i]]=a[i][n+1]/a[i][i];
for(int i=1;i<=n;i++)
printf("x%d=%f\n",i,ans[i]);
return 0;
}
附上dfs打表的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=1e5+10;
bool vis[4][100];
int ans;
void dfs(int i,int j,int n){
if(i==4){
ans++;
return;
}
int nj=j+1;
int ni=i;
if(nj==n){
nj=0;
ni++;
}
if(vis[i][j]) dfs(ni,nj,n);
else{
if(j!=n-1&&!vis[i][j+1]){
vis[i][j+1]=vis[i][j]=1;
dfs(ni,nj,n);
vis[i][j+1]=vis[i][j]=0;
}
if(i!=3&&!vis[i+1][j]){
vis[i][j]=vis[i+1][j]=1;
dfs(ni,nj,n);
vis[i][j]=vis[i+1][j]=0;
}
}
}
void make_table(int n){
for(int i=1;i<=n;i++){
ans=0;
dfs(0,0,i);
printf("%d %d\n",i,ans);
}
}
int main()
{
int n;
scanf("%d",&n);
make_table(n);
return 0;
}
E - CS Course
可以有两种方法来实现。
第一种方法:
通过前后缀和来计算,因为是从中任意删除一个,如果直接进行模拟的话,太浪费时间,而采用前后缀和的方法既简便又又节省时间。
第二种方法:
通过模拟位运算的特点;
因为与运算只要有一个为0则全部为0,或运算只要有一个是1就全部为1,
异或运算,现将全部的数字进行异或运算,然后再拿要删除的那个元素跟最后结果进行异或就能得到答案。
因此在计算与跟或的时候只需要数出每一位上的0跟1的数目,然后再跟要删除的那个数的相应位数进行比较即可。
附代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
int a[100005];
int presumand[100005];
int sufsumand[100005];
int presumor[100005];
int sufsumor[100005];
int presumno[100005];
int sufsumno[100005];
int main(){
int n,p;
while(~scanf("%d%d",&n,&p)){
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
//前前前
presumand[0]=presumor[0]=presumno[0]=a[0];
for(int i=1;i<n;i++){
presumand[i]=a[i]&presumand[i-1];
presumor[i]=presumor[i-1]|a[i];
presumno[i]=presumno[i-1]^a[i];
}
sufsumand[n-1]=sufsumor[n-1]=sufsumno[n-1]=a[n-1];
for(int i=n-2;i>=0;i--){
sufsumand[i]=a[i]&sufsumand[i+1];
sufsumor[i]=sufsumor[i+1]|a[i];
sufsumno[i]=sufsumno[i+1]^a[i];
}
int k;
while(p--){
scanf("%d",&k);
k--;
if(k==0){
printf("%d ",sufsumand[k+1]);
printf("%d ",sufsumor[k+1]);
printf("%d\n",sufsumno[k+1]);
}else if(k==n-1){
printf("%d ",presumand[k-1]);
printf("%d ",presumor[k-1]);
printf("%d\n",presumno[k-1]);
}
else{
printf("%d ",presumand[k-1]&sufsumand[k+1]);
printf("%d ",presumor[k-1]|sufsumor[k+1]);
printf("%d\n",sufsumno[k+1]^presumno[k-1]);
}
}
}
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int a[N];
int cnt[N];
int main(){
int n,p;
while(~scanf("%d%d",&n,&p)){
memset(a,0,sizeof(a));
memset(cnt,0,sizeof(cnt));
int ans3=0;
int max=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
ans3^=a[i]; //异或
int tmp=a[i];
int len=0;
while(tmp){
if(tmp%2) cnt[len]++;
tmp>>=1; //左移
len++;
if(max<len)
max=len;
}
}
for(int i=0;i<max;i++){ //0的个数
cnt[i]=n-cnt[i];
}
int op;
for(int i=0;i<p;i++){
scanf("%d",&op);
int t=a[op-1];
int ans1=0,ans2=0;
for(int j=0;j<max;j++){
if(cnt[j]==0||(cnt[j]==1&&t%2==0)) //0个数为0的话,则与,或都要运算; 如果0个数为1,而不要的数本位是0,则剩余0个数也为0
ans1+=1<<j,
ans2+=1<<j;
else if(n-cnt[j]>1||(n-cnt[j]==1&&t%2==0))
ans2+=1<<j;
t>>=1;
}
printf("%d %d %d\n",ans1,ans2,ans3^a[op-1]);
}
}
return 0;
}